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-06-04 02:06:09 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             :  */
       4             : 
       5             : #include "bgp/bgp_message_builder.h"
       6             : 
       7             : #include <vector>
       8             : 
       9             : #include "bgp/bgp_log.h"
      10             : #include "bgp/bgp_ribout.h"
      11             : #include "bgp/bgp_route.h"
      12             : #include "bgp/bgp_server.h"
      13             : #include "net/bgp_af.h"
      14             : #include "extended-community/tag.h"
      15             : #include "large-community/tag.h"
      16             : 
      17             : using std::unique_ptr;
      18             : 
      19         156 : BgpMessage::BgpMessage() : table_(NULL), datalen_(0) {
      20         156 : }
      21             : 
      22         308 : BgpMessage::~BgpMessage() {
      23         308 : }
      24             : 
      25      111223 : bool BgpMessage::StartReach(const RibOut *ribout, const RibOutAttr *roattr,
      26             :                             const BgpRoute *route) {
      27      111223 :     BgpProto::Update update;
      28      111218 :     const BgpAttr *attr = roattr->attr();
      29      111215 :     Address::Family family = table_->family();
      30             : 
      31      111215 :     BgpAttrOrigin *origin = new BgpAttrOrigin(attr->origin());
      32      111216 :     update.path_attributes.push_back(origin);
      33             : 
      34      177049 :     if ((BgpAf::FamilyToAfi(family) == BgpAf::IPv4) &&
      35       65830 :         (BgpAf::FamilyToSafi(family) == BgpAf::Unicast)) {
      36             :         BgpAttrNextHop *nh =
      37        4433 :             new BgpAttrNextHop(attr->nexthop().to_v4().to_ulong());
      38        4433 :         update.path_attributes.push_back(nh);
      39             :     }
      40             : 
      41      111218 :     if (attr->med()) {
      42       53164 :         BgpAttrMultiExitDisc *med = new BgpAttrMultiExitDisc(attr->med());
      43       53164 :         update.path_attributes.push_back(med);
      44             :     }
      45             : 
      46      111219 :     if (ribout->peer_type() == BgpProto::IBGP) {
      47       23076 :         BgpAttrLocalPref *lp = new BgpAttrLocalPref(attr->local_pref());
      48       23076 :         update.path_attributes.push_back(lp);
      49             :     }
      50             : 
      51      111220 :     if (attr->atomic_aggregate()) {
      52           2 :         BgpAttrAtomicAggregate *aa = new BgpAttrAtomicAggregate;
      53           2 :         update.path_attributes.push_back(aa);
      54             :     }
      55             : 
      56      111220 :     if (attr->aggregator_as_num()) {
      57           2 :         if (ribout->as4_supported()) {
      58             :             BgpAttr4ByteAggregator *agg = new BgpAttr4ByteAggregator(
      59           1 :                 attr->aggregator_as_num(),
      60           1 :                 attr->aggregator_adderess().to_v4().to_ulong());
      61           1 :             update.path_attributes.push_back(agg);
      62             :         } else {
      63           1 :             if (attr->aggregator_as_num() > 0xffff) {
      64             :                 // For old neighbor, need to send AS4_Aggregator along with
      65             :                 // AS_TRANS in regular aggregator attribute
      66             :                 BgpAttrAggregator *agg = new BgpAttrAggregator(
      67           0 :                     AS_TRANS, attr->aggregator_adderess().to_v4().to_ulong());
      68           0 :                 update.path_attributes.push_back(agg);
      69             :                 BgpAttrAs4Aggregator *as4_agg = new BgpAttrAs4Aggregator(
      70           0 :                     attr->aggregator_as_num(),
      71           0 :                     attr->aggregator_adderess().to_v4().to_ulong());
      72           0 :                 update.path_attributes.push_back(as4_agg);
      73             :             } else {
      74             :                 BgpAttrAggregator *agg = new BgpAttrAggregator(
      75           1 :                     attr->aggregator_as_num(),
      76           1 :                     attr->aggregator_adderess().to_v4().to_ulong());
      77           1 :                 update.path_attributes.push_back(agg);
      78             :             }
      79             :         }
      80             :     }
      81             : 
      82      111220 :     if (!attr->originator_id().is_unspecified()) {
      83             :         BgpAttrOriginatorId *originator_id =
      84           2 :             new BgpAttrOriginatorId(attr->originator_id().to_ulong());
      85           2 :         update.path_attributes.push_back(originator_id);
      86             :     }
      87             : 
      88      111221 :     if (attr->cluster_list()) {
      89             :         ClusterListSpec *clist =
      90           2 :             new ClusterListSpec(attr->cluster_list()->cluster_list());
      91           2 :         update.path_attributes.push_back(clist);
      92             :     }
      93             : 
      94             : 
      95      111221 :     if (ribout->as4_supported()) {
      96          67 :         if (attr->aspath_4byte()) {
      97             :             AsPath4ByteSpec *path = new AsPath4ByteSpec(
      98          67 :                                 attr->aspath_4byte()->path());
      99          67 :             update.path_attributes.push_back(path);
     100             :         }
     101             :     } else {
     102      111154 :         if (attr->as_path()) {
     103      109792 :             AsPathSpec *path = new AsPathSpec(attr->as_path()->path());
     104      109792 :             update.path_attributes.push_back(path);
     105             :         }
     106      111156 :         if (attr->as4_path()) {
     107           2 :             As4PathSpec *path = new As4PathSpec(attr->as4_path()->path());
     108           2 :             update.path_attributes.push_back(path);
     109             :         }
     110             :     }
     111             : 
     112      111223 :     if (attr->edge_discovery()) {
     113             :         EdgeDiscoverySpec *edspec =
     114        1045 :             new EdgeDiscoverySpec(attr->edge_discovery()->edge_discovery());
     115        1045 :         update.path_attributes.push_back(edspec);
     116             :     }
     117             : 
     118      111223 :     if (attr->edge_forwarding()) {
     119             :         EdgeForwardingSpec *efspec =
     120        1794 :             new EdgeForwardingSpec(attr->edge_forwarding()->edge_forwarding());
     121        1794 :         update.path_attributes.push_back(efspec);
     122             :     }
     123             : 
     124      111222 :     if (attr->community() && attr->community()->communities().size()) {
     125        4036 :         CommunitySpec *comm = new CommunitySpec;
     126        4036 :         comm->communities = attr->community()->communities();
     127        4035 :         update.path_attributes.push_back(comm);
     128             :     }
     129             : 
     130      111221 :     ExtCommunitySpec *ext_comm = new ExtCommunitySpec;
     131      111223 :     if (attr->ext_community() && attr->ext_community()->communities().size()) {
     132             :         const ExtCommunity::ExtCommunityList &v =
     133       89799 :                 attr->ext_community()->communities();
     134       89798 :         for (ExtCommunity::ExtCommunityList::const_iterator it = v.begin();
     135     1138267 :                 it != v.end(); ++it) {
     136     1048454 :             uint64_t value = get_value(it->data(), it->size());
     137     1048472 :             ext_comm->communities.push_back(value);
     138             :         }
     139             :     }
     140             : 
     141      111224 :     LargeCommunitySpec *large_comm = new LargeCommunitySpec;
     142      111224 :     if (attr->large_community() && attr->large_community()->communities().size()) {
     143           6 :         uint16_t tag_index = 0;
     144             :         const LargeCommunity::LargeCommunityList &v =
     145           6 :                 attr->large_community()->communities();
     146             :         uint64_t tid64;
     147             :         uint32_t asn, tid, value;
     148           6 :         for (LargeCommunity::LargeCommunityList::const_iterator it = v.begin();
     149          22 :              it != v.end(); ++it) {
     150          16 :                 TagLC tag_lc {*it};
     151          16 :                 tid64 = tag_lc.tag();
     152          16 :                 if ((tid64 & 0xFFFF0000) == 0) {
     153           8 :                     asn = tag_lc.as_number();
     154           8 :                     tid = ((tid64 & 0xFFFF00000000) >> 16) |
     155           8 :                         (tid64 & 0xFFFF);
     156           8 :                     if (asn <= AS2_MAX) {
     157           8 :                         Tag tag {as2_t(asn), tid};
     158           8 :                         ext_comm->communities.push_back(tag.GetExtCommunityValue());
     159             :                     } else {
     160           0 :                         Tag4ByteAs tag4 {asn, tag_index};
     161           0 :                         Tag tag {tag_index, tid};
     162           0 :                         ext_comm->communities.push_back(tag.GetExtCommunityValue());
     163           0 :                         ext_comm->communities.push_back(tag4.GetExtCommunityValue());
     164           0 :                         tag_index++;
     165             :                     }
     166           8 :                     continue;
     167           8 :                 }
     168             : 
     169          32 :                 for (int i = 0; i < 3; i++) {
     170          24 :                     value = get_value(it->data() + 4*i, 4);
     171          24 :                     large_comm->communities.push_back(value);
     172             :                 }
     173             :         }
     174           6 :         update.path_attributes.push_back(large_comm);
     175             :     }
     176      111219 :     if (ext_comm->EncodeLength()) {
     177       89798 :         update.path_attributes.push_back(ext_comm);
     178             :     }
     179             : 
     180      111222 :     if (attr->origin_vn_path() && attr->origin_vn_path()->origin_vns().size()) {
     181         778 :         OriginVnPathSpec *ovnpath_spec = new OriginVnPathSpec;
     182             :         const OriginVnPath::OriginVnList &v =
     183         778 :             attr->origin_vn_path()->origin_vns();
     184         778 :         for (OriginVnPath::OriginVnList::const_iterator it = v.begin();
     185        1556 :              it != v.end(); ++it) {
     186         778 :             uint64_t value = get_value(it->data(), it->size());
     187         778 :             ovnpath_spec->origin_vns.push_back(value);
     188             :         }
     189         778 :         update.path_attributes.push_back(ovnpath_spec);
     190             :     }
     191             : 
     192      111221 :     if (attr->pmsi_tunnel()) {
     193             :         PmsiTunnelSpec *pmsi_spec =
     194         528 :             new PmsiTunnelSpec(attr->pmsi_tunnel()->pmsi_tunnel());
     195         528 :         update.path_attributes.push_back(pmsi_spec);
     196             :     }
     197             : 
     198      111220 :     std::vector<uint8_t> nh;
     199             : 
     200      111217 :     route->BuildBgpProtoNextHop(nh, attr->nexthop());
     201             : 
     202             :     BgpMpNlri *nlri = new BgpMpNlri(
     203      111218 :         BgpAttribute::MPReachNlri, BgpAf::FamilyToAfi(family),
     204      111218 :         BgpAf::FamilyToSafi(family), nh);
     205      111212 :     update.path_attributes.push_back(nlri);
     206             : 
     207      111214 :     BgpProtoPrefix *prefix = new BgpProtoPrefix;
     208      111218 :     const uint32_t label = (family == Address::INET) ? 0 : roattr->label();
     209      111215 :     route->BuildProtoPrefix(prefix, attr, label, roattr->l3_label());
     210      111208 :     nlri->nlri.push_back(prefix);
     211             : 
     212      111208 :     int result = BgpProto::Encode(&update, data_, sizeof(data_),
     213      111208 :                                   &encode_offsets_, ribout->as4_supported());
     214      111218 :     if (result <= 0) {
     215         112 :         BGP_LOG_WARNING_STR(BgpMessageSend, BGP_LOG_FLAG_ALL,
     216             :             "Error encoding reach message for route " << route->ToString() <<
     217             :             " in table " << (table_ ? table_->name() : "unknown"));
     218         112 :         table_->server()->increment_message_build_error();
     219         112 :         return false;
     220             :     }
     221             : 
     222      111106 :     num_reach_route_++;
     223      111106 :     datalen_ = result;
     224      111106 :     return true;
     225      111218 : }
     226             : 
     227       45111 : bool BgpMessage::StartUnreach(const BgpRoute *route) {
     228       45111 :     BgpProto::Update update;
     229       45110 :     Address::Family family = table_->family();
     230             : 
     231             :     BgpMpNlri *nlri =
     232             :         new BgpMpNlri(BgpAttribute::MPUnreachNlri,
     233       45110 :         BgpAf::FamilyToAfi(family), BgpAf::FamilyToSafi(family));
     234       45110 :     update.path_attributes.push_back(nlri);
     235             : 
     236       45107 :     BgpProtoPrefix *prefix = new BgpProtoPrefix;
     237       45105 :     route->BuildProtoPrefix(prefix);
     238       45103 :     nlri->nlri.push_back(prefix);
     239             : 
     240             :     int result =
     241       45102 :         BgpProto::Encode(&update, data_, sizeof(data_), &encode_offsets_);
     242       45115 :     if (result <= 0) {
     243           0 :         BGP_LOG_WARNING_STR(BgpMessageSend, BGP_LOG_FLAG_ALL,
     244             :             "Error encoding unreach message for route " << route->ToString() <<
     245             :             " in table " << (table_ ? table_->name() : "unknown"));
     246           0 :         table_->server()->increment_message_build_error();
     247           0 :         return false;
     248             :     }
     249             : 
     250       45115 :     num_unreach_route_++;
     251       45115 :     datalen_ = result;
     252       45115 :     return true;
     253       45115 : }
     254             : 
     255      156328 : void BgpMessage::Reset() {
     256      156328 :     Message::Reset();
     257      156328 :     table_ = NULL;
     258      156328 :     encode_offsets_.ClearOffsets();
     259      156341 :     datalen_ = 0;
     260      156341 : }
     261             : 
     262      156328 : bool BgpMessage::Start(const RibOut *ribout, bool cache_repr,
     263             :     const RibOutAttr *roattr, const BgpRoute *route) {
     264      156328 :     Reset();
     265      156340 :     table_ = ribout->table();
     266             : 
     267      156336 :     if (roattr->IsReachable()) {
     268      111223 :         return StartReach(ribout, roattr, route);
     269             :     } else {
     270       45111 :         return StartUnreach(route);
     271             :     }
     272             : }
     273             : 
     274      183690 : bool BgpMessage::UpdateLength(const char *tag, int size, int delta) {
     275      183690 :     int offset = encode_offsets_.FindOffset(tag);
     276      183682 :     if (offset < 0) {
     277           0 :         return false;
     278             :     }
     279      183682 :     int value = get_value(&data_[offset], size);
     280      183682 :     value += delta;
     281      183682 :     put_value(&data_[offset], size, value);
     282      183684 :     return true;
     283             : }
     284             : 
     285       61255 : bool BgpMessage::AddRoute(const BgpRoute *route, const RibOutAttr *roattr) {
     286       61255 :     uint8_t *data = data_ + datalen_;
     287       61255 :     size_t size = sizeof(data_) - datalen_;
     288       61255 :     Address::Family family = table_->family();
     289             : 
     290       61254 :     BgpMpNlri nlri;
     291       61250 :     nlri.afi = BgpAf::FamilyToAfi(family);
     292       61249 :     nlri.safi = BgpAf::FamilyToSafi(family);
     293       61248 :     BgpProtoPrefix *prefix = new BgpProtoPrefix;
     294       61249 :     if (roattr) {
     295       61249 :         const uint32_t label = (family == Address::INET) ? 0 : roattr->label();
     296       61251 :         route->BuildProtoPrefix(prefix, roattr->attr(), label);
     297             :     } else {
     298           0 :         route->BuildProtoPrefix(prefix);
     299             :     }
     300       61247 :     nlri.nlri.push_back(prefix);
     301             : 
     302       61243 :     int result = BgpProto::Encode(&nlri, data, size);
     303       61250 :     if (result <= 0) {
     304          16 :         return false;
     305             :     }
     306             : 
     307       61234 :     datalen_ += result;
     308       61234 :     if (roattr->IsReachable()) {
     309       26790 :         num_reach_route_++;
     310             :     } else {
     311       34442 :         num_unreach_route_++;
     312             :     }
     313             : 
     314       61232 :     if (!UpdateLength("BgpMsgLength", 2, result)) {
     315           0 :         assert(false);
     316             :         return false;
     317             :     }
     318             : 
     319       61234 :     if (!UpdateLength("BgpPathAttribute", 2, result)) {
     320           0 :         assert(false);
     321             :         return false;
     322             :     }
     323             : 
     324       61235 :     if (!UpdateLength("MpReachUnreachNlri", 2, result)) {
     325           0 :         assert(false);
     326             :         return false;
     327             :     }
     328             : 
     329       61236 :     return true;
     330       61252 : }
     331             : 
     332      156220 : void BgpMessage::Finish() {
     333      156220 : }
     334             : 
     335      168958 : const uint8_t *BgpMessage::GetData(IPeerUpdate *peer, size_t *lenp,
     336             :     const string **msg_str, string *temp) {
     337      168958 :     *lenp = datalen_;
     338      168958 :     return data_;
     339             : }
     340             : 
     341         152 : Message *BgpMessageBuilder::Create() const {
     342         152 :     return new BgpMessage;
     343             : }
     344             : 
     345          57 : BgpMessageBuilder::BgpMessageBuilder()
     346          57 : : MessageBuilder() {
     347          57 : }

Generated by: LCOV version 1.14