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 111279 : bool BgpMessage::StartReach(const RibOut *ribout, const RibOutAttr *roattr,
26 : const BgpRoute *route) {
27 111279 : BgpProto::Update update;
28 111277 : const BgpAttr *attr = roattr->attr();
29 111275 : Address::Family family = table_->family();
30 :
31 111275 : BgpAttrOrigin *origin = new BgpAttrOrigin(attr->origin());
32 111276 : update.path_attributes.push_back(origin);
33 :
34 177142 : if ((BgpAf::FamilyToAfi(family) == BgpAf::IPv4) &&
35 65871 : (BgpAf::FamilyToSafi(family) == BgpAf::Unicast)) {
36 : BgpAttrNextHop *nh =
37 4680 : new BgpAttrNextHop(attr->nexthop().to_v4().to_ulong());
38 4680 : update.path_attributes.push_back(nh);
39 : }
40 :
41 111271 : if (attr->med()) {
42 53265 : BgpAttrMultiExitDisc *med = new BgpAttrMultiExitDisc(attr->med());
43 53265 : update.path_attributes.push_back(med);
44 : }
45 :
46 111274 : if (ribout->peer_type() == BgpProto::IBGP) {
47 23266 : BgpAttrLocalPref *lp = new BgpAttrLocalPref(attr->local_pref());
48 23266 : update.path_attributes.push_back(lp);
49 : }
50 :
51 111275 : if (attr->atomic_aggregate()) {
52 2 : BgpAttrAtomicAggregate *aa = new BgpAttrAtomicAggregate;
53 2 : update.path_attributes.push_back(aa);
54 : }
55 :
56 111274 : 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 111274 : 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 111274 : 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 111274 : 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 111206 : if (attr->as_path()) {
103 109844 : AsPathSpec *path = new AsPathSpec(attr->as_path()->path());
104 109841 : update.path_attributes.push_back(path);
105 : }
106 111208 : if (attr->as4_path()) {
107 3 : As4PathSpec *path = new As4PathSpec(attr->as4_path()->path());
108 3 : update.path_attributes.push_back(path);
109 : }
110 : }
111 :
112 111275 : if (attr->edge_discovery()) {
113 : EdgeDiscoverySpec *edspec =
114 1090 : new EdgeDiscoverySpec(attr->edge_discovery()->edge_discovery());
115 1090 : update.path_attributes.push_back(edspec);
116 : }
117 :
118 111275 : if (attr->edge_forwarding()) {
119 : EdgeForwardingSpec *efspec =
120 1807 : new EdgeForwardingSpec(attr->edge_forwarding()->edge_forwarding());
121 1807 : update.path_attributes.push_back(efspec);
122 : }
123 :
124 111275 : if (attr->community() && attr->community()->communities().size()) {
125 3999 : CommunitySpec *comm = new CommunitySpec;
126 3999 : comm->communities = attr->community()->communities();
127 3999 : update.path_attributes.push_back(comm);
128 : }
129 :
130 111275 : ExtCommunitySpec *ext_comm = new ExtCommunitySpec;
131 111274 : if (attr->ext_community() && attr->ext_community()->communities().size()) {
132 : const ExtCommunity::ExtCommunityList &v =
133 89555 : attr->ext_community()->communities();
134 89555 : for (ExtCommunity::ExtCommunityList::const_iterator it = v.begin();
135 1136941 : it != v.end(); ++it) {
136 1047380 : uint64_t value = get_value(it->data(), it->size());
137 1047403 : ext_comm->communities.push_back(value);
138 : }
139 : }
140 :
141 111265 : LargeCommunitySpec *large_comm = new LargeCommunitySpec;
142 111272 : 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 111271 : if (ext_comm->EncodeLength()) {
177 89554 : update.path_attributes.push_back(ext_comm);
178 : }
179 :
180 111275 : if (attr->origin_vn_path() && attr->origin_vn_path()->origin_vns().size()) {
181 742 : OriginVnPathSpec *ovnpath_spec = new OriginVnPathSpec;
182 : const OriginVnPath::OriginVnList &v =
183 742 : attr->origin_vn_path()->origin_vns();
184 742 : for (OriginVnPath::OriginVnList::const_iterator it = v.begin();
185 1485 : it != v.end(); ++it) {
186 743 : uint64_t value = get_value(it->data(), it->size());
187 743 : ovnpath_spec->origin_vns.push_back(value);
188 : }
189 742 : update.path_attributes.push_back(ovnpath_spec);
190 : }
191 :
192 111275 : if (attr->pmsi_tunnel()) {
193 : PmsiTunnelSpec *pmsi_spec =
194 527 : new PmsiTunnelSpec(attr->pmsi_tunnel()->pmsi_tunnel());
195 527 : update.path_attributes.push_back(pmsi_spec);
196 : }
197 :
198 111274 : std::vector<uint8_t> nh;
199 :
200 111274 : route->BuildBgpProtoNextHop(nh, attr->nexthop());
201 :
202 : BgpMpNlri *nlri = new BgpMpNlri(
203 111268 : BgpAttribute::MPReachNlri, BgpAf::FamilyToAfi(family),
204 111267 : BgpAf::FamilyToSafi(family), nh);
205 111263 : update.path_attributes.push_back(nlri);
206 :
207 111261 : BgpProtoPrefix *prefix = new BgpProtoPrefix;
208 111265 : const uint32_t label = (family == Address::INET) ? 0 : roattr->label();
209 111263 : route->BuildProtoPrefix(prefix, attr, label, roattr->l3_label());
210 111259 : nlri->nlri.push_back(prefix);
211 :
212 111255 : int result = BgpProto::Encode(&update, data_, sizeof(data_),
213 111255 : &encode_offsets_, ribout->as4_supported());
214 111275 : 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 111163 : num_reach_route_++;
223 111163 : datalen_ = result;
224 111163 : return true;
225 111275 : }
226 :
227 46430 : bool BgpMessage::StartUnreach(const BgpRoute *route) {
228 46430 : BgpProto::Update update;
229 46431 : Address::Family family = table_->family();
230 :
231 : BgpMpNlri *nlri =
232 : new BgpMpNlri(BgpAttribute::MPUnreachNlri,
233 46431 : BgpAf::FamilyToAfi(family), BgpAf::FamilyToSafi(family));
234 46427 : update.path_attributes.push_back(nlri);
235 :
236 46424 : BgpProtoPrefix *prefix = new BgpProtoPrefix;
237 46423 : route->BuildProtoPrefix(prefix);
238 46415 : nlri->nlri.push_back(prefix);
239 :
240 : int result =
241 46414 : BgpProto::Encode(&update, data_, sizeof(data_), &encode_offsets_);
242 46425 : 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 46425 : num_unreach_route_++;
251 46425 : datalen_ = result;
252 46425 : return true;
253 46425 : }
254 :
255 157698 : void BgpMessage::Reset() {
256 157698 : Message::Reset();
257 157698 : table_ = NULL;
258 157698 : encode_offsets_.ClearOffsets();
259 157711 : datalen_ = 0;
260 157711 : }
261 :
262 157696 : bool BgpMessage::Start(const RibOut *ribout, bool cache_repr,
263 : const RibOutAttr *roattr, const BgpRoute *route) {
264 157696 : Reset();
265 157710 : table_ = ribout->table();
266 :
267 157710 : if (roattr->IsReachable()) {
268 111279 : return StartReach(ribout, roattr, route);
269 : } else {
270 46430 : return StartUnreach(route);
271 : }
272 : }
273 :
274 179603 : bool BgpMessage::UpdateLength(const char *tag, int size, int delta) {
275 179603 : int offset = encode_offsets_.FindOffset(tag);
276 179588 : if (offset < 0) {
277 0 : return false;
278 : }
279 179588 : int value = get_value(&data_[offset], size);
280 179587 : value += delta;
281 179587 : put_value(&data_[offset], size, value);
282 179587 : return true;
283 : }
284 :
285 59890 : bool BgpMessage::AddRoute(const BgpRoute *route, const RibOutAttr *roattr) {
286 59890 : uint8_t *data = data_ + datalen_;
287 59890 : size_t size = sizeof(data_) - datalen_;
288 59890 : Address::Family family = table_->family();
289 :
290 59890 : BgpMpNlri nlri;
291 59885 : nlri.afi = BgpAf::FamilyToAfi(family);
292 59885 : nlri.safi = BgpAf::FamilyToSafi(family);
293 59885 : BgpProtoPrefix *prefix = new BgpProtoPrefix;
294 59885 : if (roattr) {
295 59885 : const uint32_t label = (family == Address::INET) ? 0 : roattr->label();
296 59884 : route->BuildProtoPrefix(prefix, roattr->attr(), label);
297 : } else {
298 0 : route->BuildProtoPrefix(prefix);
299 : }
300 59888 : nlri.nlri.push_back(prefix);
301 :
302 59888 : int result = BgpProto::Encode(&nlri, data, size);
303 59887 : if (result <= 0) {
304 17 : return false;
305 : }
306 :
307 59870 : datalen_ += result;
308 59870 : if (roattr->IsReachable()) {
309 26350 : num_reach_route_++;
310 : } else {
311 33520 : num_unreach_route_++;
312 : }
313 :
314 59870 : if (!UpdateLength("BgpMsgLength", 2, result)) {
315 0 : assert(false);
316 : return false;
317 : }
318 :
319 59870 : if (!UpdateLength("BgpPathAttribute", 2, result)) {
320 0 : assert(false);
321 : return false;
322 : }
323 :
324 59872 : if (!UpdateLength("MpReachUnreachNlri", 2, result)) {
325 0 : assert(false);
326 : return false;
327 : }
328 :
329 59871 : return true;
330 59888 : }
331 :
332 157587 : void BgpMessage::Finish() {
333 157587 : }
334 :
335 170329 : const uint8_t *BgpMessage::GetData(IPeerUpdate *peer, size_t *lenp,
336 : const string **msg_str, string *temp) {
337 170329 : *lenp = datalen_;
338 170329 : 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 : }
|