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: 101 203 49.8 %
Date: 2026-09-21 02:11:39 Functions: 11 13 84.6 %
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           1 : BgpMessage::BgpMessage() : table_(NULL), datalen_(0) {
      20           1 : }
      21             : 
      22           2 : BgpMessage::~BgpMessage() {
      23           2 : }
      24             : 
      25         186 : bool BgpMessage::StartReach(const RibOut *ribout, const RibOutAttr *roattr,
      26             :                             const BgpRoute *route) {
      27         186 :     BgpProto::Update update;
      28         186 :     const BgpAttr *attr = roattr->attr();
      29         186 :     Address::Family family = table_->family();
      30             : 
      31         186 :     BgpAttrOrigin *origin = new BgpAttrOrigin(attr->origin());
      32         186 :     update.path_attributes.push_back(origin);
      33             : 
      34         372 :     if ((BgpAf::FamilyToAfi(family) == BgpAf::IPv4) &&
      35         186 :         (BgpAf::FamilyToSafi(family) == BgpAf::Unicast)) {
      36             :         BgpAttrNextHop *nh =
      37          54 :             new BgpAttrNextHop(attr->nexthop().to_v4().to_ulong());
      38          54 :         update.path_attributes.push_back(nh);
      39             :     }
      40             : 
      41         186 :     if (attr->med()) {
      42           0 :         BgpAttrMultiExitDisc *med = new BgpAttrMultiExitDisc(attr->med());
      43           0 :         update.path_attributes.push_back(med);
      44             :     }
      45             : 
      46         186 :     if (ribout->peer_type() == BgpProto::IBGP) {
      47         124 :         BgpAttrLocalPref *lp = new BgpAttrLocalPref(attr->local_pref());
      48         124 :         update.path_attributes.push_back(lp);
      49             :     }
      50             : 
      51         186 :     if (attr->atomic_aggregate()) {
      52           0 :         BgpAttrAtomicAggregate *aa = new BgpAttrAtomicAggregate;
      53           0 :         update.path_attributes.push_back(aa);
      54             :     }
      55             : 
      56         186 :     if (attr->aggregator_as_num()) {
      57           0 :         if (ribout->as4_supported()) {
      58             :             BgpAttr4ByteAggregator *agg = new BgpAttr4ByteAggregator(
      59           0 :                 attr->aggregator_as_num(),
      60           0 :                 attr->aggregator_adderess().to_v4().to_ulong());
      61           0 :             update.path_attributes.push_back(agg);
      62             :         } else {
      63           0 :             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           0 :                     attr->aggregator_as_num(),
      76           0 :                     attr->aggregator_adderess().to_v4().to_ulong());
      77           0 :                 update.path_attributes.push_back(agg);
      78             :             }
      79             :         }
      80             :     }
      81             : 
      82         186 :     if (!attr->originator_id().is_unspecified()) {
      83             :         BgpAttrOriginatorId *originator_id =
      84           0 :             new BgpAttrOriginatorId(attr->originator_id().to_ulong());
      85           0 :         update.path_attributes.push_back(originator_id);
      86             :     }
      87             : 
      88         186 :     if (attr->cluster_list()) {
      89             :         ClusterListSpec *clist =
      90           0 :             new ClusterListSpec(attr->cluster_list()->cluster_list());
      91           0 :         update.path_attributes.push_back(clist);
      92             :     }
      93             : 
      94             : 
      95         186 :     if (ribout->as4_supported()) {
      96          66 :         if (attr->aspath_4byte()) {
      97             :             AsPath4ByteSpec *path = new AsPath4ByteSpec(
      98          66 :                                 attr->aspath_4byte()->path());
      99          66 :             update.path_attributes.push_back(path);
     100             :         }
     101             :     } else {
     102         120 :         if (attr->as_path()) {
     103         120 :             AsPathSpec *path = new AsPathSpec(attr->as_path()->path());
     104         120 :             update.path_attributes.push_back(path);
     105             :         }
     106         120 :         if (attr->as4_path()) {
     107           0 :             As4PathSpec *path = new As4PathSpec(attr->as4_path()->path());
     108           0 :             update.path_attributes.push_back(path);
     109             :         }
     110             :     }
     111             : 
     112         186 :     if (attr->edge_discovery()) {
     113             :         EdgeDiscoverySpec *edspec =
     114           0 :             new EdgeDiscoverySpec(attr->edge_discovery()->edge_discovery());
     115           0 :         update.path_attributes.push_back(edspec);
     116             :     }
     117             : 
     118         186 :     if (attr->edge_forwarding()) {
     119             :         EdgeForwardingSpec *efspec =
     120           0 :             new EdgeForwardingSpec(attr->edge_forwarding()->edge_forwarding());
     121           0 :         update.path_attributes.push_back(efspec);
     122             :     }
     123             : 
     124         186 :     if (attr->community() && attr->community()->communities().size()) {
     125          12 :         CommunitySpec *comm = new CommunitySpec;
     126          12 :         comm->communities = attr->community()->communities();
     127          12 :         update.path_attributes.push_back(comm);
     128             :     }
     129             : 
     130         186 :     ExtCommunitySpec *ext_comm = new ExtCommunitySpec;
     131         186 :     if (attr->ext_community() && attr->ext_community()->communities().size()) {
     132             :         const ExtCommunity::ExtCommunityList &v =
     133         132 :                 attr->ext_community()->communities();
     134         132 :         for (ExtCommunity::ExtCommunityList::const_iterator it = v.begin();
     135         340 :                 it != v.end(); ++it) {
     136         208 :             uint64_t value = get_value(it->data(), it->size());
     137         208 :             ext_comm->communities.push_back(value);
     138             :         }
     139             :     }
     140             : 
     141         186 :     LargeCommunitySpec *large_comm = new LargeCommunitySpec;
     142         186 :     if (attr->large_community() && attr->large_community()->communities().size()) {
     143           0 :         uint16_t tag_index = 0;
     144             :         const LargeCommunity::LargeCommunityList &v =
     145           0 :                 attr->large_community()->communities();
     146             :         uint64_t tid64;
     147             :         uint32_t asn, tid, value;
     148           0 :         for (LargeCommunity::LargeCommunityList::const_iterator it = v.begin();
     149           0 :              it != v.end(); ++it) {
     150           0 :                 TagLC tag_lc {*it};
     151           0 :                 tid64 = tag_lc.tag();
     152           0 :                 if ((tid64 & 0xFFFF0000) == 0) {
     153           0 :                     asn = tag_lc.as_number();
     154           0 :                     tid = ((tid64 & 0xFFFF00000000) >> 16) |
     155           0 :                         (tid64 & 0xFFFF);
     156           0 :                     if (asn <= AS2_MAX) {
     157           0 :                         Tag tag {as2_t(asn), tid};
     158           0 :                         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           0 :                     continue;
     167           0 :                 }
     168             : 
     169           0 :                 for (int i = 0; i < 3; i++) {
     170           0 :                     value = get_value(it->data() + 4*i, 4);
     171           0 :                     large_comm->communities.push_back(value);
     172             :                 }
     173             :         }
     174           0 :         update.path_attributes.push_back(large_comm);
     175             :     }
     176         186 :     if (ext_comm->EncodeLength()) {
     177         132 :         update.path_attributes.push_back(ext_comm);
     178             :     }
     179             : 
     180         186 :     if (attr->origin_vn_path() && attr->origin_vn_path()->origin_vns().size()) {
     181           0 :         OriginVnPathSpec *ovnpath_spec = new OriginVnPathSpec;
     182             :         const OriginVnPath::OriginVnList &v =
     183           0 :             attr->origin_vn_path()->origin_vns();
     184           0 :         for (OriginVnPath::OriginVnList::const_iterator it = v.begin();
     185           0 :              it != v.end(); ++it) {
     186           0 :             uint64_t value = get_value(it->data(), it->size());
     187           0 :             ovnpath_spec->origin_vns.push_back(value);
     188             :         }
     189           0 :         update.path_attributes.push_back(ovnpath_spec);
     190             :     }
     191             : 
     192         186 :     if (attr->pmsi_tunnel()) {
     193             :         PmsiTunnelSpec *pmsi_spec =
     194           0 :             new PmsiTunnelSpec(attr->pmsi_tunnel()->pmsi_tunnel());
     195           0 :         update.path_attributes.push_back(pmsi_spec);
     196             :     }
     197             : 
     198         186 :     std::vector<uint8_t> nh;
     199             : 
     200         186 :     route->BuildBgpProtoNextHop(nh, attr->nexthop());
     201             : 
     202             :     BgpMpNlri *nlri = new BgpMpNlri(
     203         186 :         BgpAttribute::MPReachNlri, BgpAf::FamilyToAfi(family),
     204         186 :         BgpAf::FamilyToSafi(family), nh);
     205         186 :     update.path_attributes.push_back(nlri);
     206             : 
     207         186 :     BgpProtoPrefix *prefix = new BgpProtoPrefix;
     208         186 :     const uint32_t label = (family == Address::INET) ? 0 : roattr->label();
     209         186 :     route->BuildProtoPrefix(prefix, attr, label, roattr->l3_label());
     210         186 :     nlri->nlri.push_back(prefix);
     211             : 
     212         186 :     int result = BgpProto::Encode(&update, data_, sizeof(data_),
     213         186 :                                   &encode_offsets_, ribout->as4_supported());
     214         186 :     if (result <= 0) {
     215           0 :         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           0 :         table_->server()->increment_message_build_error();
     219           0 :         return false;
     220             :     }
     221             : 
     222         186 :     num_reach_route_++;
     223         186 :     datalen_ = result;
     224         186 :     return true;
     225         186 : }
     226             : 
     227          98 : bool BgpMessage::StartUnreach(const BgpRoute *route) {
     228          98 :     BgpProto::Update update;
     229          98 :     Address::Family family = table_->family();
     230             : 
     231             :     BgpMpNlri *nlri =
     232             :         new BgpMpNlri(BgpAttribute::MPUnreachNlri,
     233          98 :         BgpAf::FamilyToAfi(family), BgpAf::FamilyToSafi(family));
     234          98 :     update.path_attributes.push_back(nlri);
     235             : 
     236          98 :     BgpProtoPrefix *prefix = new BgpProtoPrefix;
     237          98 :     route->BuildProtoPrefix(prefix);
     238          98 :     nlri->nlri.push_back(prefix);
     239             : 
     240             :     int result =
     241          98 :         BgpProto::Encode(&update, data_, sizeof(data_), &encode_offsets_);
     242          98 :     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          98 :     num_unreach_route_++;
     251          98 :     datalen_ = result;
     252          98 :     return true;
     253          98 : }
     254             : 
     255         284 : void BgpMessage::Reset() {
     256         284 :     Message::Reset();
     257         284 :     table_ = NULL;
     258         284 :     encode_offsets_.ClearOffsets();
     259         284 :     datalen_ = 0;
     260         284 : }
     261             : 
     262         284 : bool BgpMessage::Start(const RibOut *ribout, bool cache_repr,
     263             :     const RibOutAttr *roattr, const BgpRoute *route) {
     264         284 :     Reset();
     265         284 :     table_ = ribout->table();
     266             : 
     267         284 :     if (roattr->IsReachable()) {
     268         186 :         return StartReach(ribout, roattr, route);
     269             :     } else {
     270          98 :         return StartUnreach(route);
     271             :     }
     272             : }
     273             : 
     274           0 : bool BgpMessage::UpdateLength(const char *tag, int size, int delta) {
     275           0 :     int offset = encode_offsets_.FindOffset(tag);
     276           0 :     if (offset < 0) {
     277           0 :         return false;
     278             :     }
     279           0 :     int value = get_value(&data_[offset], size);
     280           0 :     value += delta;
     281           0 :     put_value(&data_[offset], size, value);
     282           0 :     return true;
     283             : }
     284             : 
     285           0 : bool BgpMessage::AddRoute(const BgpRoute *route, const RibOutAttr *roattr) {
     286           0 :     uint8_t *data = data_ + datalen_;
     287           0 :     size_t size = sizeof(data_) - datalen_;
     288           0 :     Address::Family family = table_->family();
     289             : 
     290           0 :     BgpMpNlri nlri;
     291           0 :     nlri.afi = BgpAf::FamilyToAfi(family);
     292           0 :     nlri.safi = BgpAf::FamilyToSafi(family);
     293           0 :     BgpProtoPrefix *prefix = new BgpProtoPrefix;
     294           0 :     if (roattr) {
     295           0 :         const uint32_t label = (family == Address::INET) ? 0 : roattr->label();
     296           0 :         route->BuildProtoPrefix(prefix, roattr->attr(), label);
     297             :     } else {
     298           0 :         route->BuildProtoPrefix(prefix);
     299             :     }
     300           0 :     nlri.nlri.push_back(prefix);
     301             : 
     302           0 :     int result = BgpProto::Encode(&nlri, data, size);
     303           0 :     if (result <= 0) {
     304           0 :         return false;
     305             :     }
     306             : 
     307           0 :     datalen_ += result;
     308           0 :     if (roattr->IsReachable()) {
     309           0 :         num_reach_route_++;
     310             :     } else {
     311           0 :         num_unreach_route_++;
     312             :     }
     313             : 
     314           0 :     if (!UpdateLength("BgpMsgLength", 2, result)) {
     315           0 :         assert(false);
     316             :         return false;
     317             :     }
     318             : 
     319           0 :     if (!UpdateLength("BgpPathAttribute", 2, result)) {
     320           0 :         assert(false);
     321             :         return false;
     322             :     }
     323             : 
     324           0 :     if (!UpdateLength("MpReachUnreachNlri", 2, result)) {
     325           0 :         assert(false);
     326             :         return false;
     327             :     }
     328             : 
     329           0 :     return true;
     330           0 : }
     331             : 
     332         284 : void BgpMessage::Finish() {
     333         284 : }
     334             : 
     335         284 : const uint8_t *BgpMessage::GetData(IPeerUpdate *peer, size_t *lenp,
     336             :     const string **msg_str, string *temp) {
     337         284 :     *lenp = datalen_;
     338         284 :     return data_;
     339             : }
     340             : 
     341           1 : Message *BgpMessageBuilder::Create() const {
     342           1 :     return new BgpMessage;
     343             : }
     344             : 
     345           1 : BgpMessageBuilder::BgpMessageBuilder()
     346           1 : : MessageBuilder() {
     347           1 : }

Generated by: LCOV version 1.14