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 9 : BgpMessage::BgpMessage() : table_(NULL), datalen_(0) {
20 9 : }
21 :
22 18 : BgpMessage::~BgpMessage() {
23 18 : }
24 :
25 13154 : bool BgpMessage::StartReach(const RibOut *ribout, const RibOutAttr *roattr,
26 : const BgpRoute *route) {
27 13154 : BgpProto::Update update;
28 13153 : const BgpAttr *attr = roattr->attr();
29 13153 : Address::Family family = table_->family();
30 :
31 13153 : BgpAttrOrigin *origin = new BgpAttrOrigin(attr->origin());
32 13153 : update.path_attributes.push_back(origin);
33 :
34 19994 : if ((BgpAf::FamilyToAfi(family) == BgpAf::IPv4) &&
35 6842 : (BgpAf::FamilyToSafi(family) == BgpAf::Unicast)) {
36 : BgpAttrNextHop *nh =
37 24 : new BgpAttrNextHop(attr->nexthop().to_v4().to_ulong());
38 24 : update.path_attributes.push_back(nh);
39 : }
40 :
41 13152 : if (attr->med()) {
42 6885 : BgpAttrMultiExitDisc *med = new BgpAttrMultiExitDisc(attr->med());
43 6886 : update.path_attributes.push_back(med);
44 : }
45 :
46 13154 : if (ribout->peer_type() == BgpProto::IBGP) {
47 30 : BgpAttrLocalPref *lp = new BgpAttrLocalPref(attr->local_pref());
48 30 : update.path_attributes.push_back(lp);
49 : }
50 :
51 13153 : if (attr->atomic_aggregate()) {
52 0 : BgpAttrAtomicAggregate *aa = new BgpAttrAtomicAggregate;
53 0 : update.path_attributes.push_back(aa);
54 : }
55 :
56 13153 : 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 13153 : 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 13152 : 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 13152 : if (ribout->as4_supported()) {
96 0 : if (attr->aspath_4byte()) {
97 : AsPath4ByteSpec *path = new AsPath4ByteSpec(
98 0 : attr->aspath_4byte()->path());
99 0 : update.path_attributes.push_back(path);
100 : }
101 : } else {
102 13151 : if (attr->as_path()) {
103 13152 : AsPathSpec *path = new AsPathSpec(attr->as_path()->path());
104 13155 : update.path_attributes.push_back(path);
105 : }
106 13154 : 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 13154 : 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 13154 : 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 13154 : if (attr->community() && attr->community()->communities().size()) {
125 0 : CommunitySpec *comm = new CommunitySpec;
126 0 : comm->communities = attr->community()->communities();
127 0 : update.path_attributes.push_back(comm);
128 : }
129 :
130 13154 : ExtCommunitySpec *ext_comm = new ExtCommunitySpec;
131 13154 : if (attr->ext_community() && attr->ext_community()->communities().size()) {
132 : const ExtCommunity::ExtCommunityList &v =
133 11622 : attr->ext_community()->communities();
134 11622 : for (ExtCommunity::ExtCommunityList::const_iterator it = v.begin();
135 80184 : it != v.end(); ++it) {
136 68550 : uint64_t value = get_value(it->data(), it->size());
137 68557 : ext_comm->communities.push_back(value);
138 : }
139 : }
140 :
141 13155 : LargeCommunitySpec *large_comm = new LargeCommunitySpec;
142 13156 : 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 13155 : if (ext_comm->EncodeLength()) {
177 11623 : update.path_attributes.push_back(ext_comm);
178 : }
179 :
180 13154 : 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 13153 : 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 13153 : std::vector<uint8_t> nh;
199 :
200 13152 : route->BuildBgpProtoNextHop(nh, attr->nexthop());
201 :
202 : BgpMpNlri *nlri = new BgpMpNlri(
203 13150 : BgpAttribute::MPReachNlri, BgpAf::FamilyToAfi(family),
204 13150 : BgpAf::FamilyToSafi(family), nh);
205 13151 : update.path_attributes.push_back(nlri);
206 :
207 13150 : BgpProtoPrefix *prefix = new BgpProtoPrefix;
208 13152 : const uint32_t label = (family == Address::INET) ? 0 : roattr->label();
209 13152 : route->BuildProtoPrefix(prefix, attr, label, roattr->l3_label());
210 13152 : nlri->nlri.push_back(prefix);
211 :
212 13151 : int result = BgpProto::Encode(&update, data_, sizeof(data_),
213 13151 : &encode_offsets_, ribout->as4_supported());
214 13154 : 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 13154 : num_reach_route_++;
223 13154 : datalen_ = result;
224 13154 : return true;
225 13154 : }
226 :
227 4009 : bool BgpMessage::StartUnreach(const BgpRoute *route) {
228 4009 : BgpProto::Update update;
229 4007 : Address::Family family = table_->family();
230 :
231 : BgpMpNlri *nlri =
232 : new BgpMpNlri(BgpAttribute::MPUnreachNlri,
233 4007 : BgpAf::FamilyToAfi(family), BgpAf::FamilyToSafi(family));
234 4008 : update.path_attributes.push_back(nlri);
235 :
236 4005 : BgpProtoPrefix *prefix = new BgpProtoPrefix;
237 4005 : route->BuildProtoPrefix(prefix);
238 4002 : nlri->nlri.push_back(prefix);
239 :
240 : int result =
241 4004 : BgpProto::Encode(&update, data_, sizeof(data_), &encode_offsets_);
242 4007 : 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 4007 : num_unreach_route_++;
251 4007 : datalen_ = result;
252 4007 : return true;
253 4007 : }
254 :
255 17152 : void BgpMessage::Reset() {
256 17152 : Message::Reset();
257 17151 : table_ = NULL;
258 17151 : encode_offsets_.ClearOffsets();
259 17164 : datalen_ = 0;
260 17164 : }
261 :
262 17151 : bool BgpMessage::Start(const RibOut *ribout, bool cache_repr,
263 : const RibOutAttr *roattr, const BgpRoute *route) {
264 17151 : Reset();
265 17164 : table_ = ribout->table();
266 :
267 17164 : if (roattr->IsReachable()) {
268 13154 : return StartReach(ribout, roattr, route);
269 : } else {
270 4009 : return StartUnreach(route);
271 : }
272 : }
273 :
274 14309 : bool BgpMessage::UpdateLength(const char *tag, int size, int delta) {
275 14309 : int offset = encode_offsets_.FindOffset(tag);
276 14309 : if (offset < 0) {
277 0 : return false;
278 : }
279 14309 : int value = get_value(&data_[offset], size);
280 14309 : value += delta;
281 14309 : put_value(&data_[offset], size, value);
282 14309 : return true;
283 : }
284 :
285 4770 : bool BgpMessage::AddRoute(const BgpRoute *route, const RibOutAttr *roattr) {
286 4770 : uint8_t *data = data_ + datalen_;
287 4770 : size_t size = sizeof(data_) - datalen_;
288 4770 : Address::Family family = table_->family();
289 :
290 4770 : BgpMpNlri nlri;
291 4770 : nlri.afi = BgpAf::FamilyToAfi(family);
292 4770 : nlri.safi = BgpAf::FamilyToSafi(family);
293 4770 : BgpProtoPrefix *prefix = new BgpProtoPrefix;
294 4770 : if (roattr) {
295 4770 : const uint32_t label = (family == Address::INET) ? 0 : roattr->label();
296 4770 : route->BuildProtoPrefix(prefix, roattr->attr(), label);
297 : } else {
298 0 : route->BuildProtoPrefix(prefix);
299 : }
300 4771 : nlri.nlri.push_back(prefix);
301 :
302 4770 : int result = BgpProto::Encode(&nlri, data, size);
303 4770 : if (result <= 0) {
304 0 : return false;
305 : }
306 :
307 4770 : datalen_ += result;
308 4770 : if (roattr->IsReachable()) {
309 2622 : num_reach_route_++;
310 : } else {
311 2148 : num_unreach_route_++;
312 : }
313 :
314 4770 : if (!UpdateLength("BgpMsgLength", 2, result)) {
315 0 : assert(false);
316 : return false;
317 : }
318 :
319 4771 : if (!UpdateLength("BgpPathAttribute", 2, result)) {
320 0 : assert(false);
321 : return false;
322 : }
323 :
324 4771 : if (!UpdateLength("MpReachUnreachNlri", 2, result)) {
325 0 : assert(false);
326 : return false;
327 : }
328 :
329 4771 : return true;
330 4771 : }
331 :
332 17161 : void BgpMessage::Finish() {
333 17161 : }
334 :
335 17155 : const uint8_t *BgpMessage::GetData(IPeerUpdate *peer, size_t *lenp,
336 : const string **msg_str, string *temp) {
337 17155 : *lenp = datalen_;
338 17155 : return data_;
339 : }
340 :
341 9 : Message *BgpMessageBuilder::Create() const {
342 9 : return new BgpMessage;
343 : }
344 :
345 3 : BgpMessageBuilder::BgpMessageBuilder()
346 3 : : MessageBuilder() {
347 3 : }
|