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 : }
|