LCOV - code coverage report
Current view: top level - bgp - xmpp_message_builder.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 397 413 96.1 %
Date: 2026-11-09 02:10:49 Functions: 31 31 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include "bgp/xmpp_message_builder.h"
       7             : 
       8             : #include <boost/foreach.hpp>
       9             : 
      10             : #include <algorithm>
      11             : 
      12             : #include "bgp/ipeer.h"
      13             : #include "bgp/bgp_server.h"
      14             : #include "bgp/bgp_table.h"
      15             : #include "bgp/extended-community/etree.h"
      16             : #include "bgp/extended-community/mac_mobility.h"
      17             : #include "bgp/ermvpn/ermvpn_route.h"
      18             : #include "bgp/evpn/evpn_route.h"
      19             : #include "bgp/mvpn/mvpn_route.h"
      20             : #include "bgp/routing-instance/routing_instance.h"
      21             : #include "bgp/security_group/security_group.h"
      22             : #include "db/db.h"
      23             : #include "net/community_type.h"
      24             : #include "schema/xmpp_multicast_types.h"
      25             : #include "schema/xmpp_mvpn_types.h"
      26             : #include "schema/xmpp_enet_types.h"
      27             : #include "xmpp/xmpp_init.h"
      28             : 
      29             : using pugi::xml_attribute;
      30             : using pugi::xml_document;
      31             : using pugi::xml_node;
      32             : using std::ostringstream;
      33             : using std::copy;
      34             : using std::fill;
      35             : using std::string;
      36             : using std::stringstream;
      37             : using std::vector;
      38             : 
      39      468473 : static inline const char *AfiName(uint16_t afi) {
      40      468473 :     switch (afi) {
      41      263996 :     case BgpAf::IPv4:
      42      263996 :         return "1";
      43             :         break;
      44      194127 :     case BgpAf::IPv6:
      45      194127 :         return "2";
      46             :         break;
      47       10397 :     case BgpAf::L2Vpn:
      48       10397 :         return "25";
      49             :         break;
      50             :     }
      51           0 :     assert(false);
      52             :     return NULL;
      53             : }
      54             : 
      55      468500 : static inline const char *XmppSafiName(uint8_t safi) {
      56      468500 :     switch (safi) {
      57      448932 :     case BgpAf::Unicast:
      58      448932 :         return "1";
      59             :         break;
      60          11 :     case BgpAf::Mpls:
      61          11 :         return "4";
      62             :         break;
      63        6475 :     case BgpAf::MVpn:
      64        6475 :         return "5";
      65             :         break;
      66        2700 :     case BgpAf::Mcast:
      67        2700 :         return "241";
      68             :         break;
      69       10397 :     case BgpAf::Enet:
      70       10397 :         return "242";
      71             :         break;
      72             :     }
      73           0 :     assert(false);
      74             :     return NULL;
      75             : }
      76             : 
      77         144 : BgpXmppMessage::BgpXmppMessage()
      78         144 :     : table_(NULL),
      79         144 :       writer_(XmlWriter(&repr_)),
      80         144 :       is_reachable_(false),
      81         144 :       cache_routes_(false),
      82         144 :       repr_valid_(false),
      83         144 :       mobility_(0, false),
      84         288 :       etree_leaf_(false) {
      85         144 :     msg_begin_.reserve(kMaxFromToLength);
      86         144 : }
      87             : 
      88         288 : BgpXmppMessage::~BgpXmppMessage() {
      89         288 : }
      90             : 
      91      468415 : void BgpXmppMessage::Reset() {
      92      468415 :     Message::Reset();
      93      468415 :     table_ = NULL;
      94      468415 :     is_reachable_ = false;
      95      468415 :     cache_routes_ = false;
      96      468415 :     repr_valid_ = false;
      97      468415 :     repr_.clear();
      98      468416 : }
      99             : 
     100      468408 : bool BgpXmppMessage::Start(const RibOut *ribout, bool cache_routes,
     101             :     const RibOutAttr *roattr, const BgpRoute *route) {
     102      468408 :     Reset();
     103      468413 :     table_ = ribout->table();
     104      468417 :     is_reachable_ = roattr->IsReachable();
     105      468403 :     cache_routes_ = cache_routes;
     106      468403 :     Address::Family family = table_->family();
     107             : 
     108      468398 :     if (is_reachable_) {
     109      318315 :         const BgpAttr *attr = roattr->attr();
     110      318315 :         ProcessCommunity(attr->community());
     111      318295 :         ProcessExtCommunity(attr->ext_community());
     112             :     }
     113             : 
     114             :     // Reserve space for the begin line that contains the message opening tag
     115             :     // with from and to attributes. Actual value gets patched in when GetData
     116             :     // is called.
     117      468422 :     repr_.append(kMaxFromToLength, ' ');
     118             : 
     119             :     // Add opening tags for event and items. The closing tags are added when
     120             :     // GetData is called.
     121      468419 :     repr_ += "\n\t<event xmlns=\"http://jabber.org/protocol/pubsub\">";
     122      468458 :     repr_ += "\n\t\t<items node=\"";
     123      468486 :     repr_ += AfiName(BgpAf::FamilyToAfi(family));
     124      468515 :     repr_ += "/";
     125      468533 :     repr_ += XmppSafiName(BgpAf::FamilyToXmppSafi(family));
     126      468506 :     repr_ += "/";
     127      468508 :     repr_ += table_->routing_instance()->name();
     128      468503 :     repr_ += "\">\n";
     129             : 
     130      468514 :     if (table_->family() == Address::ERMVPN) {
     131        2700 :         AddMcastRoute(route, roattr);
     132      465807 :     } else if (table_->family() == Address::EVPN) {
     133       10397 :         AddEnetRoute(route, roattr);
     134      455397 :     } else if (table_->family() == Address::INET6) {
     135      194124 :         AddInet6Route(route, roattr);
     136      261264 :     } else if (table_->family() == Address::MVPN) {
     137        6475 :         AddMvpnRoute(route, roattr);
     138             :     } else {
     139      254793 :         AddInetRoute(route, roattr);
     140             :     }
     141      468530 :     return true;
     142             : }
     143             : 
     144      468526 : void BgpXmppMessage::Finish() {
     145      468526 : }
     146             : 
     147      621298 : bool BgpXmppMessage::AddRoute(const BgpRoute *route, const RibOutAttr *roattr) {
     148      621298 :     assert(is_reachable_ == roattr->IsReachable());
     149      621296 :     if (is_reachable_ && num_reach_route_ >= kMaxReachCount)
     150         184 :         return false;
     151      621112 :     if (!is_reachable_ && num_unreach_route_ >= kMaxUnreachCount)
     152           8 :         return false;
     153             : 
     154      621104 :     if (is_reachable_) {
     155      518598 :         const BgpAttr *attr = roattr->attr();
     156      518592 :         ProcessCommunity(attr->community());
     157      518592 :         ProcessExtCommunity(attr->ext_community());
     158             :     }
     159             : 
     160      621118 :     if (table_->family() == Address::ERMVPN) {
     161         103 :         return AddMcastRoute(route, roattr);
     162      621011 :     } else if (table_->family() == Address::EVPN) {
     163        2114 :         return AddEnetRoute(route, roattr);
     164      618895 :     } else if (table_->family() == Address::INET6) {
     165      126616 :         return AddInet6Route(route, roattr);
     166      492280 :     } else if (table_->family() == Address::MVPN) {
     167      190464 :         return AddMvpnRoute(route, roattr);
     168             :     } else {
     169      301851 :         return AddInetRoute(route, roattr);
     170             :     }
     171             : }
     172             : 
     173      531240 : void BgpXmppMessage::EncodeNextHop(const BgpRoute *route,
     174             :                                    const RibOutAttr::NextHop &nexthop,
     175             :                                    autogen::ItemType *item) {
     176      531240 :     autogen::NextHopType item_nexthop;
     177             : 
     178      531240 :     const IpAddress &address = nexthop.address();
     179      531234 :     if (address.is_v4()) {
     180      527942 :         item_nexthop.af = BgpAf::IPv4;
     181      527942 :         item_nexthop.address = address.to_v4().to_string();
     182             :     } else {
     183        3283 :         item_nexthop.af = BgpAf::IPv6;
     184        3283 :         item_nexthop.address = address.to_v6().to_string();
     185             :     }
     186      531540 :     item_nexthop.label = nexthop.label();
     187      531523 :     item_nexthop.virtual_network = GetVirtualNetwork(nexthop);
     188      531525 :     item_nexthop.tag_list.tag = nexthop.tag_list();
     189      531352 :     item_nexthop.is_new_tags_list = true;
     190             : 
     191             :     // If there's a non-zero label and encap list is empty use mpls over gre
     192             :     // as default encap.
     193      531352 :     if (item_nexthop.label) {
     194      522408 :         vector<string> &encap_list =
     195             :             item_nexthop.tunnel_encapsulation_list.tunnel_encapsulation;
     196      522408 :         if (nexthop.encap().empty()) {
     197      100567 :             encap_list.push_back(string("gre"));
     198             :         } else {
     199      421829 :             encap_list = nexthop.encap();
     200             :         }
     201             :     }
     202             : 
     203      531294 :     item->entry.next_hops.next_hop.push_back(item_nexthop);
     204      531358 : }
     205             : 
     206      627313 : void BgpXmppMessage::AddIpReach(const BgpRoute *route,
     207             :                                 const RibOutAttr *roattr) {
     208      627313 :     if (!roattr->repr().empty()) {
     209       98208 :         repr_ += roattr->repr();
     210       98208 :         return;
     211             :     }
     212      529110 :     Address::Family family = table_->family();
     213             : 
     214      529110 :     autogen::ItemType item;
     215      529060 :     item.entry.nlri.af = BgpAf::FamilyToAfi(family);
     216      529055 :     item.entry.nlri.safi = BgpAf::FamilyToXmppSafi(family);
     217      529059 :     item.entry.nlri.address = route->ToString();
     218      529141 :     item.entry.version = 1;
     219      529141 :     item.entry.virtual_network = GetVirtualNetwork(route, roattr);
     220      529140 :     item.entry.local_preference = roattr->attr()->local_pref();
     221      529099 :     item.entry.med = roattr->attr()->med();
     222      529076 :     item.entry.sequence_number = mobility_.sequence_number;
     223      529076 :     item.entry.mobility.seqno = mobility_.sequence_number;
     224      529076 :     item.entry.mobility.sticky = mobility_.sticky;
     225             : 
     226      529076 :     assert(!roattr->nexthop_list().empty());
     227             : 
     228             :     // Encode all next-hops in the list.
     229     1591653 :     BOOST_FOREACH(const RibOutAttr::NextHop &nexthop, roattr->nexthop_list()) {
     230      531261 :         EncodeNextHop(route, nexthop, &item);
     231             :     }
     232             : 
     233      529026 :     for (vector<int>::const_iterator it = security_group_list_.begin();
     234      851981 :          it != security_group_list_.end(); ++it) {
     235      322988 :         item.entry.security_group_list.security_group.push_back(*it);
     236             :     }
     237             : 
     238      528977 :     for (vector<string>::const_iterator it = community_list_.begin();
     239      540798 :          it != community_list_.end(); ++it) {
     240       11830 :         item.entry.community_tag_list.community_tag.push_back(*it);
     241             :     }
     242             : 
     243             :     // Encode load balance attribute.
     244      528967 :     if (!load_balance_attribute_.IsDefault())
     245           4 :         load_balance_attribute_.Encode(&item.entry.load_balance);
     246             : 
     247      528970 :     xml_node node = doc_.append_child("item");
     248      528900 :     node.append_attribute("id") = route->ToXmppIdString().c_str();
     249             : 
     250             :     // Remember the previous size.
     251             :     // Using remove_child instead of reset allows memory pages allocated for
     252             :     // the xml_document to be reused during the lifetime of the xml_document.
     253      529008 :     size_t pos = repr_.size();
     254      528996 :     item.Encode(&node);
     255      528964 :     doc_.print(writer_, "\t", pugi::format_default, pugi::encoding_auto, 3);
     256      529134 :     doc_.remove_child(node);
     257             : 
     258             :     // Cache the substring starting at the previous size.
     259      529108 :     if (cache_routes_)
     260       28011 :         roattr->set_repr(repr_, pos);
     261      529109 : }
     262             : 
     263      250023 : void BgpXmppMessage::AddIpUnreach(const BgpRoute *route) {
     264      250023 :     repr_ += "\t\t\t<retract id=\"" + route->ToXmppIdString() + "\" />\n";
     265      250121 : }
     266             : 
     267      556643 : bool BgpXmppMessage::AddInetRoute(const BgpRoute *route,
     268             :                                   const RibOutAttr *roattr) {
     269      556643 :     if (is_reachable_) {
     270      424850 :         num_reach_route_++;
     271      424850 :         AddIpReach(route, roattr);
     272             :     } else {
     273      131793 :         num_unreach_route_++;
     274      131793 :         AddIpUnreach(route);
     275             :     }
     276      556705 :     return true;
     277             : }
     278             : 
     279      320730 : bool BgpXmppMessage::AddInet6Route(const BgpRoute *route,
     280             :                                    const RibOutAttr *roattr) {
     281      320730 :     if (is_reachable_) {
     282      202479 :         num_reach_route_++;
     283      202479 :         AddIpReach(route, roattr);
     284             :     } else {
     285      118251 :         num_unreach_route_++;
     286      118251 :         AddIpUnreach(route);
     287             :     }
     288      320740 :     return true;
     289             : }
     290             : 
     291        9071 : void BgpXmppMessage::EncodeEnetNextHop(const BgpRoute *route,
     292             :                                        const RibOutAttr::NextHop &nexthop,
     293             :                                        autogen::EnetItemType *item) {
     294        9071 :     autogen::EnetNextHopType item_nexthop;
     295             : 
     296        9071 :     item_nexthop.af = BgpAf::IPv4;
     297        9071 :     item_nexthop.address = nexthop.address().to_v4().to_string();
     298        9070 :     item_nexthop.label = nexthop.label();
     299        9071 :     item_nexthop.l3_label = nexthop.l3_label();
     300        9071 :     if (!nexthop.mac().IsZero())
     301          20 :         item_nexthop.mac = nexthop.mac().ToString();
     302             : 
     303             :     // If encap list is empty use mpls over gre as default encap.
     304        9071 :     vector<string> &encap_list =
     305             :         item_nexthop.tunnel_encapsulation_list.tunnel_encapsulation;
     306        9071 :     if (nexthop.encap().empty()) {
     307           0 :         encap_list.push_back(string("gre"));
     308             :     } else {
     309        9071 :         encap_list = nexthop.encap();
     310             :     }
     311        9071 :     item_nexthop.tag_list.tag = nexthop.tag_list();
     312        9070 :     item_nexthop.is_new_tags_list = true;
     313        9070 :     item->entry.next_hops.next_hop.push_back(item_nexthop);
     314        9071 : }
     315             : 
     316       10519 : void BgpXmppMessage::AddEnetReach(const BgpRoute *route,
     317             :                                   const RibOutAttr *roattr) {
     318       10519 :     if (!roattr->repr().empty()) {
     319           0 :         repr_ += roattr->repr();
     320           0 :         return;
     321             :     }
     322       10519 :     Address::Family family = table_->family();
     323             : 
     324       10519 :     autogen::EnetItemType item;
     325       10519 :     item.entry.nlri.af = BgpAf::FamilyToAfi(family);
     326       10519 :     item.entry.nlri.safi = BgpAf::FamilyToXmppSafi(family);
     327             : 
     328       10519 :     EvpnRoute *evpn_route =
     329             :         static_cast<EvpnRoute *>(const_cast<BgpRoute *>(route));
     330       10519 :     const EvpnPrefix &evpn_prefix = evpn_route->GetPrefix();
     331       10519 :     item.entry.nlri.ethernet_tag = evpn_prefix.tag();
     332       10519 :     item.entry.nlri.mac = evpn_prefix.mac_addr().ToString();
     333       21038 :     item.entry.nlri.address = evpn_prefix.ip_address().to_string() + "/" +
     334       31557 :         integerToString(evpn_prefix.ip_address_length());
     335       10519 :     item.entry.nlri.source = evpn_prefix.source().to_string();
     336       10519 :     item.entry.nlri.group = evpn_prefix.group().to_string();
     337             : 
     338       10519 :     item.entry.virtual_network = GetVirtualNetwork(route, roattr);
     339       10519 :     item.entry.local_preference = roattr->attr()->local_pref();
     340       10519 :     item.entry.med = roattr->attr()->med();
     341       10519 :     item.entry.sequence_number = mobility_.sequence_number;
     342       10519 :     item.entry.mobility.seqno = mobility_.sequence_number;
     343       10519 :     item.entry.mobility.sticky = mobility_.sticky;
     344       10519 :     item.entry.etree_leaf = etree_leaf_;
     345             : 
     346       10519 :     for (vector<int>::const_iterator it = security_group_list_.begin();
     347       21046 :          it != security_group_list_.end(); ++it) {
     348       10527 :         item.entry.security_group_list.security_group.push_back(*it);
     349             :     }
     350             : 
     351       10519 :     const BgpOList *olist = roattr->attr()->olist().get();
     352       10519 :     assert((olist == NULL) != roattr->nexthop_list().empty());
     353             : 
     354       10519 :     if (olist) {
     355        1576 :         assert(olist->olist().subcode == BgpAttribute::OList);
     356       14778 :         BOOST_FOREACH(const BgpOListElem *elem, olist->elements()) {
     357        6601 :             autogen::EnetNextHopType nh;
     358        6601 :             nh.af = BgpAf::IPv4;
     359        6601 :             nh.address = elem->address.to_string();
     360        6601 :             nh.label = elem->label;
     361        6601 :             nh.tunnel_encapsulation_list.tunnel_encapsulation = elem->encap;
     362        6601 :             item.entry.olist.next_hop.push_back(nh);
     363        6601 :         }
     364             :     }
     365             : 
     366       10519 :     const BgpOList *leaf_olist = roattr->attr()->leaf_olist().get();
     367       10519 :     assert((leaf_olist == NULL) != roattr->nexthop_list().empty());
     368             : 
     369       10519 :     if (leaf_olist) {
     370        1576 :         assert(leaf_olist->olist().subcode == BgpAttribute::LeafOList);
     371        1576 :         BOOST_FOREACH(const BgpOListElem *elem, leaf_olist->elements()) {
     372           0 :             autogen::EnetNextHopType nh;
     373           0 :             nh.af = BgpAf::IPv4;
     374           0 :             nh.address = elem->address.to_string();
     375           0 :             nh.label = elem->label;
     376           0 :             nh.tunnel_encapsulation_list.tunnel_encapsulation = elem->encap;
     377           0 :             item.entry.leaf_olist.next_hop.push_back(nh);
     378           0 :         }
     379             :     }
     380             : 
     381       28661 :     BOOST_FOREACH(const RibOutAttr::NextHop &nexthop, roattr->nexthop_list()) {
     382        9071 :         EncodeEnetNextHop(route, nexthop, &item);
     383             :     }
     384             : 
     385       11429 :     for (const auto &peer_name : route->peer_sources()) {
     386         910 :         item.entry.peers.peer.push_back(peer_name);
     387             :     }
     388             : 
     389       10519 :     xml_node node = doc_.append_child("item");
     390       10519 :     node.append_attribute("id") = route->ToXmppIdString().c_str();
     391             : 
     392             :     // Remember the previous size.
     393             :     // Using remove_child instead of reset allows memory pages allocated for
     394             :     // the xml_document to be reused during the lifetime of the xml_document.
     395       10519 :     size_t pos = repr_.size();
     396       10519 :     item.Encode(&node);
     397       10519 :     doc_.print(writer_, "\t", pugi::format_default, pugi::encoding_auto, 3);
     398       10519 :     doc_.remove_child(node);
     399             : 
     400             :     // Cache the substring starting at the previous size.
     401       10519 :     if (cache_routes_)
     402        2009 :         roattr->set_repr(repr_, pos);
     403       10519 : }
     404             : 
     405        1992 : void BgpXmppMessage::AddEnetUnreach(const BgpRoute *route) {
     406        1992 :     repr_ += "\t\t\t<retract id=\"" + route->ToXmppIdString() + "\" />\n";
     407        1992 : }
     408             : 
     409       12511 : bool BgpXmppMessage::AddEnetRoute(const BgpRoute *route,
     410             :     const RibOutAttr *roattr) {
     411       12511 :     if (is_reachable_) {
     412       10519 :         num_reach_route_++;
     413       10519 :         AddEnetReach(route, roattr);
     414             :     } else {
     415        1992 :         num_unreach_route_++;
     416        1992 :         AddEnetUnreach(route);
     417             :     }
     418       12511 :     return true;
     419             : }
     420             : 
     421             : //
     422             : // Note that there's no need to cache the string representation since a given
     423             : // mcast route is sent to exactly one xmpp peer.
     424             : //
     425        2329 : void BgpXmppMessage::AddMcastReach(const BgpRoute *route,
     426             :                                    const RibOutAttr *roattr) {
     427        2329 :     Address::Family family = table_->family();
     428        2329 :     autogen::McastItemType item;
     429        2329 :     item.entry.nlri.af = BgpAf::FamilyToAfi(family);
     430        2329 :     item.entry.nlri.safi = BgpAf::FamilyToXmppSafi(family);
     431             : 
     432        2329 :     ErmVpnRoute *ermvpn_route =
     433             :         static_cast<ErmVpnRoute *>(const_cast<BgpRoute *>(route));
     434        2329 :     item.entry.nlri.group = ermvpn_route->GetPrefix().group().to_string();
     435        2329 :     item.entry.nlri.source =  ermvpn_route->GetPrefix().source().to_string();
     436        2329 :     item.entry.nlri.source_label = roattr->label();
     437        2329 :     if (!roattr->source_address().is_unspecified()) {
     438             :         item.entry.nlri.source_address =
     439         147 :            roattr->source_address().to_string();
     440             :     }
     441             : 
     442        2329 :     const BgpOList *olist = roattr->attr()->olist().get();
     443        2329 :     assert(olist->olist().subcode == BgpAttribute::OList);
     444        7349 :     BOOST_FOREACH(const BgpOListElem *elem, olist->elements()) {
     445        2510 :         autogen::McastNextHopType nh;
     446        2510 :         nh.af = BgpAf::IPv4;
     447        2510 :         nh.address = elem->address.to_string();
     448        2510 :         nh.label = integerToString(elem->label);
     449        2510 :         nh.tunnel_encapsulation_list.tunnel_encapsulation = elem->encap;
     450        2510 :         item.entry.olist.next_hop.push_back(nh);
     451        2510 :     }
     452             : 
     453             :     // Using remove_child instead of reset allows memory pages allocated for
     454             :     // the xml_document to be reused during the lifetime of the xml_document.
     455        2329 :     xml_node node = doc_.append_child("item");
     456        2329 :     node.append_attribute("id") = route->ToXmppIdString().c_str();
     457        2329 :     item.Encode(&node);
     458        2329 :     doc_.print(writer_, "\t", pugi::format_default, pugi::encoding_auto, 3);
     459        2329 :     doc_.remove_child(node);
     460        2329 : }
     461             : 
     462         474 : void BgpXmppMessage::AddMcastUnreach(const BgpRoute *route) {
     463         474 :     repr_ += "\t\t\t<retract id=\"" + route->ToXmppIdString() + "\" />\n";
     464         474 : }
     465             : 
     466        2803 : bool BgpXmppMessage::AddMcastRoute(const BgpRoute *route,
     467             :                                    const RibOutAttr *roattr) {
     468        2803 :     if (is_reachable_) {
     469        2329 :         num_reach_route_++;
     470        2329 :         AddMcastReach(route, roattr);
     471             :     } else {
     472         474 :         num_unreach_route_++;
     473         474 :         AddMcastUnreach(route);
     474             :     }
     475        2803 :     return true;
     476             : }
     477             : 
     478      196816 : void BgpXmppMessage::AddMvpnReach(const BgpRoute *route,
     479             :                                   const RibOutAttr *roattr) {
     480      196816 :     Address::Family family = table_->family();
     481      196816 :     autogen::MvpnItemType item;
     482      196816 :     item.entry.nlri.af = BgpAf::FamilyToAfi(family);
     483      196816 :     item.entry.nlri.safi = BgpAf::FamilyToXmppSafi(family);
     484             : 
     485      196816 :     MvpnRoute *mvpn_route =
     486             :         static_cast<MvpnRoute *>(const_cast<BgpRoute *>(route));
     487      196816 :     item.entry.nlri.group = mvpn_route->GetPrefix().group().to_string();
     488      196816 :     item.entry.nlri.source =  mvpn_route->GetPrefix().source().to_string();
     489      196816 :     item.entry.nlri.route_type = mvpn_route->GetPrefix().type();
     490      196816 :     assert((item.entry.nlri.route_type == MvpnPrefix::SourceActiveADRoute) ||
     491             :             (item.entry.nlri.route_type == MvpnPrefix::SourceTreeJoinRoute));
     492             : 
     493      196816 :     if (item.entry.nlri.route_type == MvpnPrefix::SourceActiveADRoute) {
     494      196722 :         const BgpOList *olist = roattr->attr()->olist().get();
     495      196722 :         assert(olist->olist().subcode == BgpAttribute::OList);
     496      590166 :         BOOST_FOREACH(const BgpOListElem *elem, olist->elements()) {
     497      196722 :             autogen::MvpnNextHopType nh;
     498      196722 :             nh.af = BgpAf::IPv4;
     499      196722 :             nh.address = elem->address.to_string();
     500      196722 :             nh.label = elem->label;
     501      196722 :             nh.tunnel_encapsulation_list.tunnel_encapsulation = elem->encap;
     502      196722 :             item.entry.olist.next_hop.push_back(nh);
     503      196722 :         }
     504             :     }
     505             : 
     506             :     // Using remove_child instead of reset allows memory pages allocated for
     507             :     // the xml_document to be reused during the lifetime of the xml_document.
     508      196816 :     xml_node node = doc_.append_child("item");
     509      196816 :     node.append_attribute("id") = route->ToXmppIdString().c_str();
     510      196816 :     item.Encode(&node);
     511      196816 :     doc_.print(writer_, "\t", pugi::format_default, pugi::encoding_auto, 3);
     512      196816 :     doc_.remove_child(node);
     513      196816 : }
     514             : 
     515         123 : void BgpXmppMessage::AddMvpnUnreach(const BgpRoute *route) {
     516         123 :     repr_ += "\t\t\t<retract id=\"" + route->ToXmppIdString() + "\" />\n";
     517         123 : }
     518             : 
     519      196939 : bool BgpXmppMessage::AddMvpnRoute(const BgpRoute *route,
     520             :                                    const RibOutAttr *roattr) {
     521      196939 :     if (is_reachable_) {
     522      196816 :         num_reach_route_++;
     523      196816 :         AddMvpnReach(route, roattr);
     524             :     } else {
     525         123 :         num_unreach_route_++;
     526         123 :         AddMvpnUnreach(route);
     527             :     }
     528      196939 :     return true;
     529             : }
     530             : 
     531    14152859 : const uint8_t *BgpXmppMessage::GetData(IPeerUpdate *peer, size_t *lenp,
     532             :     const string **msg_str, string *temp) {
     533             :     // Build begin line that contains message opening tag with from and to
     534             :     // attributes.
     535    14152859 :     msg_begin_.clear();
     536    14152922 :     msg_begin_ += "\n<message from=\"";
     537    14153013 :     msg_begin_ += XmppInit::kControlNodeJID;
     538    14153118 :     msg_begin_ += "\" to=\"";
     539    14153204 :     msg_begin_ += peer->ToString();
     540    14153318 :     msg_begin_ += "/";
     541    14153330 :     msg_begin_ += XmppInit::kBgpPeer;
     542    14153286 :     msg_begin_ += "\">";
     543             : 
     544             :     // Add closing tags if this is the first peer to which the message will
     545             :     // be sent.
     546    14153300 :     if (!repr_valid_) {
     547      468584 :         repr_ += "\t\t</items>\n\t</event>\n</message>\n";
     548      468582 :         repr_valid_ = true;
     549             :     }
     550             : 
     551             :     // Replace the begin line if it fits in the space reserved at the start
     552             :     // of repr_. Use fill and copy instead of string::replace as the latter
     553             :     // seems to construct a new temporary string to hold the input data to
     554             :     // be copied.
     555             :     // Otherwise build a new string with the begin line and the rest of the
     556             :     // message in repr_.
     557    14153298 :     size_t begin_size = msg_begin_.size();
     558    14153251 :     if (begin_size <= kMaxFromToLength) {
     559     9958963 :         size_t extra = kMaxFromToLength - begin_size;
     560     9958963 :         char *data = const_cast<char *>(repr_.c_str());
     561     9958973 :         fill(data, data + extra, ' ');
     562     9958936 :         copy(msg_begin_.c_str(), msg_begin_.c_str() + begin_size, data + extra);
     563     9958769 :         *lenp = repr_.size() - extra;
     564     9958764 :         *msg_str = &repr_;
     565     9958764 :         return reinterpret_cast<const uint8_t *>(repr_.c_str()) + extra;
     566             :     } else {
     567     4194288 :         *temp = msg_begin_ + string(repr_, kMaxFromToLength);
     568     4194304 :         *lenp = temp->size();
     569     4194304 :         *msg_str = NULL;
     570     4194304 :         return reinterpret_cast<const uint8_t *>(temp->c_str());
     571             :     }
     572             : }
     573             : 
     574      836877 : void BgpXmppMessage::ProcessCommunity(const Community *community) {
     575      836877 :     community_list_.clear();
     576      836882 :     if (community == NULL)
     577      825076 :         return;
     578       35451 :     BOOST_FOREACH(uint32_t value, community->communities()) {
     579       11827 :         community_list_.push_back(CommunityType::CommunityToString(value));
     580             :     }
     581             : }
     582             : 
     583      836856 : void BgpXmppMessage::ProcessExtCommunity(const ExtCommunity *ext_community) {
     584      836856 :     mobility_.sequence_number = 0;
     585      836856 :     mobility_.sticky = false;
     586      836856 :     etree_leaf_ = false;
     587      836856 :     security_group_list_.clear();
     588      836863 :     load_balance_attribute_ = LoadBalance::LoadBalanceAttribute();
     589      837077 :     if (ext_community == NULL)
     590      207993 :         return;
     591             : 
     592      629084 :     as_t as_number =  table_->server()->autonomous_system();
     593      629039 :     bool sg_asn_match = true;
     594      629008 :     for (ExtCommunity::ExtCommunityList::const_iterator iter =
     595      629039 :         ext_community->communities().begin();
     596     3684950 :         iter != ext_community->communities().end(); ++iter) {
     597     3055991 :         if (ExtCommunity::is_security_group(*iter)) {
     598      431857 :             SecurityGroup sg(*iter);
     599      431849 :             if (as_number <= AS2_MAX)
     600      235242 :                 if (sg.as_number() != as_number && !sg.IsGlobal())
     601           2 :                     continue;
     602      431867 :             security_group_list_.push_back(sg.security_group_id());
     603     2624227 :         } else if (ExtCommunity::is_security_group4(*iter)) {
     604      196608 :             SecurityGroup4ByteAs sg(*iter);
     605      196608 :             if (sg.as_number() != as_number)
     606           0 :                 sg_asn_match = false;
     607     2427559 :         } else if (ExtCommunity::is_mac_mobility(*iter)) {
     608        1079 :             MacMobility mm(*iter);
     609        1079 :             mobility_.sequence_number = mm.sequence_number();
     610        1079 :             mobility_.sticky = mm.sticky();
     611     2426469 :         } else if (ExtCommunity::is_load_balance(*iter)) {
     612           4 :             LoadBalance load_balance(*iter);
     613           4 :             load_balance.FillAttribute(&load_balance_attribute_);
     614     2426452 :         } else if (ExtCommunity::is_etree(*iter)) {
     615        9385 :             ETree etree(*iter);
     616        9385 :             etree_leaf_ = etree.leaf();
     617             :         }
     618             :     }
     619      628915 :     if (!sg_asn_match)
     620           0 :         security_group_list_.clear();
     621             : }
     622             : 
     623     1069456 : string BgpXmppMessage::GetVirtualNetwork(
     624             :     const RibOutAttr::NextHop &nexthop) const {
     625     1069456 :     int index = nexthop.origin_vn_index();
     626     1069460 :     if (index > 0) {
     627             :         const RoutingInstanceMgr *manager =
     628       68942 :             table_->routing_instance()->manager();
     629       68946 :         return manager->GetVirtualNetworkByVnIndex(index);
     630     1000518 :     } else if (index == 0) {
     631       61341 :         return table_->routing_instance()->GetVirtualNetworkName();
     632             :     } else {
     633      939177 :         return "unresolved";
     634             :     }
     635             : }
     636             : 
     637      539639 : string BgpXmppMessage::GetVirtualNetwork(const BgpRoute *route,
     638             :     const RibOutAttr *roattr) const {
     639      539639 :     if (!is_reachable_) {
     640           0 :         return "unresolved";
     641      539639 :     } else if (roattr->nexthop_list().empty()) {
     642        1576 :         if (roattr->vrf_originated()) {
     643        1576 :             return table_->routing_instance()->GetVirtualNetworkName();
     644             :         } else {
     645           0 :             return "unresolved";
     646             :         }
     647             :     } else {
     648      538000 :         return GetVirtualNetwork(roattr->nexthop_list().front());
     649             :     }
     650             : }
     651             : 
     652          50 : BgpXmppMessageBuilder::BgpXmppMessageBuilder() {
     653          50 : }
     654             : 
     655         144 : Message *BgpXmppMessageBuilder::Create() const {
     656         144 :     return new BgpXmppMessage;
     657             : }

Generated by: LCOV version 1.14