LCOV - code coverage report
Current view: top level - bgp - bgp_message_builder.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 185 203 91.1 %
Date: 2026-11-09 02:10:49 Functions: 13 13 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/bgp_message_builder.h"
       7             : 
       8             : #include <vector>
       9             : 
      10             : #include "bgp/bgp_log.h"
      11             : #include "bgp/bgp_ribout.h"
      12             : #include "bgp/bgp_route.h"
      13             : #include "bgp/bgp_server.h"
      14             : #include "net/bgp_af.h"
      15             : #include "extended-community/tag.h"
      16             : #include "large-community/tag.h"
      17             : 
      18             : using std::unique_ptr;
      19             : 
      20         156 : BgpMessage::BgpMessage() : table_(NULL), datalen_(0) {
      21         156 : }
      22             : 
      23         308 : BgpMessage::~BgpMessage() {
      24         308 : }
      25             : 
      26      111523 : bool BgpMessage::StartReach(const RibOut *ribout, const RibOutAttr *roattr,
      27             :                             const BgpRoute *route) {
      28      111523 :     BgpProto::Update update;
      29      111526 :     const BgpAttr *attr = roattr->attr();
      30      111524 :     Address::Family family = table_->family();
      31             : 
      32      111524 :     BgpAttrOrigin *origin = new BgpAttrOrigin(attr->origin());
      33      111520 :     update.path_attributes.push_back(origin);
      34             : 
      35      177292 :     if ((BgpAf::FamilyToAfi(family) == BgpAf::IPv4) &&
      36       65781 :         (BgpAf::FamilyToSafi(family) == BgpAf::Unicast)) {
      37             :         BgpAttrNextHop *nh =
      38        4466 :             new BgpAttrNextHop(attr->nexthop().to_v4().to_ulong());
      39        4466 :         update.path_attributes.push_back(nh);
      40             :     }
      41             : 
      42      111511 :     if (attr->med()) {
      43       53507 :         BgpAttrMultiExitDisc *med = new BgpAttrMultiExitDisc(attr->med());
      44       53508 :         update.path_attributes.push_back(med);
      45             :     }
      46             : 
      47      111514 :     if (ribout->peer_type() == BgpProto::IBGP) {
      48       22949 :         BgpAttrLocalPref *lp = new BgpAttrLocalPref(attr->local_pref());
      49       22950 :         update.path_attributes.push_back(lp);
      50             :     }
      51             : 
      52      111516 :     if (attr->atomic_aggregate()) {
      53           2 :         BgpAttrAtomicAggregate *aa = new BgpAttrAtomicAggregate;
      54           2 :         update.path_attributes.push_back(aa);
      55             :     }
      56             : 
      57      111517 :     if (attr->aggregator_as_num()) {
      58           2 :         if (ribout->as4_supported()) {
      59             :             BgpAttr4ByteAggregator *agg = new BgpAttr4ByteAggregator(
      60           1 :                 attr->aggregator_as_num(),
      61           1 :                 attr->aggregator_adderess().to_v4().to_ulong());
      62           1 :             update.path_attributes.push_back(agg);
      63             :         } else {
      64           1 :             if (attr->aggregator_as_num() > 0xffff) {
      65             :                 // For old neighbor, need to send AS4_Aggregator along with
      66             :                 // AS_TRANS in regular aggregator attribute
      67             :                 BgpAttrAggregator *agg = new BgpAttrAggregator(
      68           0 :                     AS_TRANS, attr->aggregator_adderess().to_v4().to_ulong());
      69           0 :                 update.path_attributes.push_back(agg);
      70             :                 BgpAttrAs4Aggregator *as4_agg = new BgpAttrAs4Aggregator(
      71           0 :                     attr->aggregator_as_num(),
      72           0 :                     attr->aggregator_adderess().to_v4().to_ulong());
      73           0 :                 update.path_attributes.push_back(as4_agg);
      74             :             } else {
      75             :                 BgpAttrAggregator *agg = new BgpAttrAggregator(
      76           1 :                     attr->aggregator_as_num(),
      77           1 :                     attr->aggregator_adderess().to_v4().to_ulong());
      78           1 :                 update.path_attributes.push_back(agg);
      79             :             }
      80             :         }
      81             :     }
      82             : 
      83      111518 :     if (!attr->originator_id().is_unspecified()) {
      84             :         BgpAttrOriginatorId *originator_id =
      85           2 :             new BgpAttrOriginatorId(attr->originator_id().to_ulong());
      86           2 :         update.path_attributes.push_back(originator_id);
      87             :     }
      88             : 
      89      111520 :     if (attr->cluster_list()) {
      90             :         ClusterListSpec *clist =
      91           2 :             new ClusterListSpec(attr->cluster_list()->cluster_list());
      92           2 :         update.path_attributes.push_back(clist);
      93             :     }
      94             : 
      95             : 
      96      111515 :     if (ribout->as4_supported()) {
      97          67 :         if (attr->aspath_4byte()) {
      98             :             AsPath4ByteSpec *path = new AsPath4ByteSpec(
      99          67 :                                 attr->aspath_4byte()->path());
     100          67 :             update.path_attributes.push_back(path);
     101             :         }
     102             :     } else {
     103      111445 :         if (attr->as_path()) {
     104      110084 :             AsPathSpec *path = new AsPathSpec(attr->as_path()->path());
     105      110086 :             update.path_attributes.push_back(path);
     106             :         }
     107      111457 :         if (attr->as4_path()) {
     108           5 :             As4PathSpec *path = new As4PathSpec(attr->as4_path()->path());
     109           5 :             update.path_attributes.push_back(path);
     110             :         }
     111             :     }
     112             : 
     113      111523 :     if (attr->edge_discovery()) {
     114             :         EdgeDiscoverySpec *edspec =
     115        1052 :             new EdgeDiscoverySpec(attr->edge_discovery()->edge_discovery());
     116        1052 :         update.path_attributes.push_back(edspec);
     117             :     }
     118             : 
     119      111522 :     if (attr->edge_forwarding()) {
     120             :         EdgeForwardingSpec *efspec =
     121        1704 :             new EdgeForwardingSpec(attr->edge_forwarding()->edge_forwarding());
     122        1704 :         update.path_attributes.push_back(efspec);
     123             :     }
     124             : 
     125      111523 :     if (attr->community() && attr->community()->communities().size()) {
     126        4063 :         CommunitySpec *comm = new CommunitySpec;
     127        4062 :         comm->communities = attr->community()->communities();
     128        4063 :         update.path_attributes.push_back(comm);
     129             :     }
     130             : 
     131      111523 :     ExtCommunitySpec *ext_comm = new ExtCommunitySpec;
     132      111519 :     if (attr->ext_community() && attr->ext_community()->communities().size()) {
     133             :         const ExtCommunity::ExtCommunityList &v =
     134       90198 :                 attr->ext_community()->communities();
     135       90203 :         for (ExtCommunity::ExtCommunityList::const_iterator it = v.begin();
     136     1141658 :                 it != v.end(); ++it) {
     137     1051440 :             uint64_t value = get_value(it->data(), it->size());
     138     1051458 :             ext_comm->communities.push_back(value);
     139             :         }
     140             :     }
     141             : 
     142      111528 :     LargeCommunitySpec *large_comm = new LargeCommunitySpec;
     143      111527 :     if (attr->large_community() && attr->large_community()->communities().size()) {
     144           6 :         uint16_t tag_index = 0;
     145             :         const LargeCommunity::LargeCommunityList &v =
     146           6 :                 attr->large_community()->communities();
     147             :         uint64_t tid64;
     148             :         uint32_t asn, tid, value;
     149           6 :         for (LargeCommunity::LargeCommunityList::const_iterator it = v.begin();
     150          22 :              it != v.end(); ++it) {
     151          16 :                 TagLC tag_lc {*it};
     152          16 :                 tid64 = tag_lc.tag();
     153          16 :                 if ((tid64 & 0xFFFF0000) == 0) {
     154           8 :                     asn = tag_lc.as_number();
     155           8 :                     tid = ((tid64 & 0xFFFF00000000) >> 16) |
     156           8 :                         (tid64 & 0xFFFF);
     157           8 :                     if (asn <= AS2_MAX) {
     158           8 :                         Tag tag {as2_t(asn), tid};
     159           8 :                         ext_comm->communities.push_back(tag.GetExtCommunityValue());
     160             :                     } else {
     161           0 :                         Tag4ByteAs tag4 {asn, tag_index};
     162           0 :                         Tag tag {tag_index, tid};
     163           0 :                         ext_comm->communities.push_back(tag.GetExtCommunityValue());
     164           0 :                         ext_comm->communities.push_back(tag4.GetExtCommunityValue());
     165           0 :                         tag_index++;
     166             :                     }
     167           8 :                     continue;
     168           8 :                 }
     169             : 
     170          32 :                 for (int i = 0; i < 3; i++) {
     171          24 :                     value = get_value(it->data() + 4*i, 4);
     172          24 :                     large_comm->communities.push_back(value);
     173             :                 }
     174             :         }
     175           6 :         update.path_attributes.push_back(large_comm);
     176             :     }
     177      111522 :     if (ext_comm->EncodeLength()) {
     178       90208 :         update.path_attributes.push_back(ext_comm);
     179             :     }
     180             : 
     181      111530 :     if (attr->origin_vn_path() && attr->origin_vn_path()->origin_vns().size()) {
     182         752 :         OriginVnPathSpec *ovnpath_spec = new OriginVnPathSpec;
     183             :         const OriginVnPath::OriginVnList &v =
     184         752 :             attr->origin_vn_path()->origin_vns();
     185         752 :         for (OriginVnPath::OriginVnList::const_iterator it = v.begin();
     186        1505 :              it != v.end(); ++it) {
     187         753 :             uint64_t value = get_value(it->data(), it->size());
     188         753 :             ovnpath_spec->origin_vns.push_back(value);
     189             :         }
     190         752 :         update.path_attributes.push_back(ovnpath_spec);
     191             :     }
     192             : 
     193      111532 :     if (attr->pmsi_tunnel()) {
     194             :         PmsiTunnelSpec *pmsi_spec =
     195         526 :             new PmsiTunnelSpec(attr->pmsi_tunnel()->pmsi_tunnel());
     196         526 :         update.path_attributes.push_back(pmsi_spec);
     197             :     }
     198             : 
     199      111529 :     std::vector<uint8_t> nh;
     200             : 
     201      111520 :     route->BuildBgpProtoNextHop(nh, attr->nexthop());
     202             : 
     203             :     BgpMpNlri *nlri = new BgpMpNlri(
     204      111518 :         BgpAttribute::MPReachNlri, BgpAf::FamilyToAfi(family),
     205      111519 :         BgpAf::FamilyToSafi(family), nh);
     206      111523 :     update.path_attributes.push_back(nlri);
     207             : 
     208      111522 :     BgpProtoPrefix *prefix = new BgpProtoPrefix;
     209      111526 :     const uint32_t label = (family == Address::INET) ? 0 : roattr->label();
     210      111521 :     route->BuildProtoPrefix(prefix, attr, label, roattr->l3_label());
     211      111511 :     nlri->nlri.push_back(prefix);
     212             : 
     213      111501 :     int result = BgpProto::Encode(&update, data_, sizeof(data_),
     214      111503 :                                   &encode_offsets_, ribout->as4_supported());
     215      111520 :     if (result <= 0) {
     216         112 :         BGP_LOG_WARNING_STR(BgpMessageSend, BGP_LOG_FLAG_ALL,
     217             :             "Error encoding reach message for route " << route->ToString() <<
     218             :             " in table " << (table_ ? table_->name() : "unknown"));
     219         112 :         table_->server()->increment_message_build_error();
     220         112 :         return false;
     221             :     }
     222             : 
     223      111408 :     num_reach_route_++;
     224      111408 :     datalen_ = result;
     225      111408 :     return true;
     226      111520 : }
     227             : 
     228       43776 : bool BgpMessage::StartUnreach(const BgpRoute *route) {
     229       43776 :     BgpProto::Update update;
     230       43778 :     Address::Family family = table_->family();
     231             : 
     232             :     BgpMpNlri *nlri =
     233             :         new BgpMpNlri(BgpAttribute::MPUnreachNlri,
     234       43776 :         BgpAf::FamilyToAfi(family), BgpAf::FamilyToSafi(family));
     235       43771 :     update.path_attributes.push_back(nlri);
     236             : 
     237       43769 :     BgpProtoPrefix *prefix = new BgpProtoPrefix;
     238       43772 :     route->BuildProtoPrefix(prefix);
     239       43765 :     nlri->nlri.push_back(prefix);
     240             : 
     241             :     int result =
     242       43766 :         BgpProto::Encode(&update, data_, sizeof(data_), &encode_offsets_);
     243       43780 :     if (result <= 0) {
     244           0 :         BGP_LOG_WARNING_STR(BgpMessageSend, BGP_LOG_FLAG_ALL,
     245             :             "Error encoding unreach message for route " << route->ToString() <<
     246             :             " in table " << (table_ ? table_->name() : "unknown"));
     247           0 :         table_->server()->increment_message_build_error();
     248           0 :         return false;
     249             :     }
     250             : 
     251       43780 :     num_unreach_route_++;
     252       43780 :     datalen_ = result;
     253       43780 :     return true;
     254       43780 : }
     255             : 
     256      155297 : void BgpMessage::Reset() {
     257      155297 :     Message::Reset();
     258      155297 :     table_ = NULL;
     259      155297 :     encode_offsets_.ClearOffsets();
     260      155314 :     datalen_ = 0;
     261      155314 : }
     262             : 
     263      155299 : bool BgpMessage::Start(const RibOut *ribout, bool cache_repr,
     264             :     const RibOutAttr *roattr, const BgpRoute *route) {
     265      155299 :     Reset();
     266      155309 :     table_ = ribout->table();
     267             : 
     268      155302 :     if (roattr->IsReachable()) {
     269      111522 :         return StartReach(ribout, roattr, route);
     270             :     } else {
     271       43775 :         return StartUnreach(route);
     272             :     }
     273             : }
     274             : 
     275      190007 : bool BgpMessage::UpdateLength(const char *tag, int size, int delta) {
     276      190007 :     int offset = encode_offsets_.FindOffset(tag);
     277      189985 :     if (offset < 0) {
     278           0 :         return false;
     279             :     }
     280      189985 :     int value = get_value(&data_[offset], size);
     281      189984 :     value += delta;
     282      189984 :     put_value(&data_[offset], size, value);
     283      189990 :     return true;
     284             : }
     285             : 
     286       63354 : bool BgpMessage::AddRoute(const BgpRoute *route, const RibOutAttr *roattr) {
     287       63354 :     uint8_t *data = data_ + datalen_;
     288       63354 :     size_t size = sizeof(data_) - datalen_;
     289       63354 :     Address::Family family = table_->family();
     290             : 
     291       63354 :     BgpMpNlri nlri;
     292       63352 :     nlri.afi = BgpAf::FamilyToAfi(family);
     293       63351 :     nlri.safi = BgpAf::FamilyToSafi(family);
     294       63350 :     BgpProtoPrefix *prefix = new BgpProtoPrefix;
     295       63350 :     if (roattr) {
     296       63350 :         const uint32_t label = (family == Address::INET) ? 0 : roattr->label();
     297       63348 :         route->BuildProtoPrefix(prefix, roattr->attr(), label);
     298             :     } else {
     299           0 :         route->BuildProtoPrefix(prefix);
     300             :     }
     301       63350 :     nlri.nlri.push_back(prefix);
     302             : 
     303       63354 :     int result = BgpProto::Encode(&nlri, data, size);
     304       63353 :     if (result <= 0) {
     305          16 :         return false;
     306             :     }
     307             : 
     308       63337 :     datalen_ += result;
     309       63337 :     if (roattr->IsReachable()) {
     310       26379 :         num_reach_route_++;
     311             :     } else {
     312       36958 :         num_unreach_route_++;
     313             :     }
     314             : 
     315       63337 :     if (!UpdateLength("BgpMsgLength", 2, result)) {
     316           0 :         assert(false);
     317             :         return false;
     318             :     }
     319             : 
     320       63344 :     if (!UpdateLength("BgpPathAttribute", 2, result)) {
     321           0 :         assert(false);
     322             :         return false;
     323             :     }
     324             : 
     325       63343 :     if (!UpdateLength("MpReachUnreachNlri", 2, result)) {
     326           0 :         assert(false);
     327             :         return false;
     328             :     }
     329             : 
     330       63340 :     return true;
     331       63356 : }
     332             : 
     333      155178 : void BgpMessage::Finish() {
     334      155178 : }
     335             : 
     336      167854 : const uint8_t *BgpMessage::GetData(IPeerUpdate *peer, size_t *lenp,
     337             :     const string **msg_str, string *temp) {
     338      167854 :     *lenp = datalen_;
     339      167854 :     return data_;
     340             : }
     341             : 
     342         152 : Message *BgpMessageBuilder::Create() const {
     343         152 :     return new BgpMessage;
     344             : }
     345             : 
     346          57 : BgpMessageBuilder::BgpMessageBuilder()
     347          57 : : MessageBuilder() {
     348          57 : }

Generated by: LCOV version 1.14