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 110986 : bool BgpMessage::StartReach(const RibOut *ribout, const RibOutAttr *roattr,
26 : const BgpRoute *route) {
27 110986 : BgpProto::Update update;
28 110980 : const BgpAttr *attr = roattr->attr();
29 110980 : Address::Family family = table_->family();
30 :
31 110979 : BgpAttrOrigin *origin = new BgpAttrOrigin(attr->origin());
32 110977 : update.path_attributes.push_back(origin);
33 :
34 176844 : if ((BgpAf::FamilyToAfi(family) == BgpAf::IPv4) &&
35 65873 : (BgpAf::FamilyToSafi(family) == BgpAf::Unicast)) {
36 : BgpAttrNextHop *nh =
37 4628 : new BgpAttrNextHop(attr->nexthop().to_v4().to_ulong());
38 4628 : update.path_attributes.push_back(nh);
39 : }
40 :
41 110970 : if (attr->med()) {
42 53008 : BgpAttrMultiExitDisc *med = new BgpAttrMultiExitDisc(attr->med());
43 53008 : update.path_attributes.push_back(med);
44 : }
45 :
46 110974 : if (ribout->peer_type() == BgpProto::IBGP) {
47 23263 : BgpAttrLocalPref *lp = new BgpAttrLocalPref(attr->local_pref());
48 23263 : update.path_attributes.push_back(lp);
49 : }
50 :
51 110978 : if (attr->atomic_aggregate()) {
52 2 : BgpAttrAtomicAggregate *aa = new BgpAttrAtomicAggregate;
53 2 : update.path_attributes.push_back(aa);
54 : }
55 :
56 110978 : 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 110976 : 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 110978 : 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 110977 : 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 110908 : if (attr->as_path()) {
103 109548 : AsPathSpec *path = new AsPathSpec(attr->as_path()->path());
104 109548 : update.path_attributes.push_back(path);
105 : }
106 110912 : if (attr->as4_path()) {
107 4 : As4PathSpec *path = new As4PathSpec(attr->as4_path()->path());
108 4 : update.path_attributes.push_back(path);
109 : }
110 : }
111 :
112 110978 : if (attr->edge_discovery()) {
113 : EdgeDiscoverySpec *edspec =
114 1044 : new EdgeDiscoverySpec(attr->edge_discovery()->edge_discovery());
115 1044 : update.path_attributes.push_back(edspec);
116 : }
117 :
118 110978 : if (attr->edge_forwarding()) {
119 : EdgeForwardingSpec *efspec =
120 1719 : new EdgeForwardingSpec(attr->edge_forwarding()->edge_forwarding());
121 1719 : update.path_attributes.push_back(efspec);
122 : }
123 :
124 110978 : if (attr->community() && attr->community()->communities().size()) {
125 4011 : CommunitySpec *comm = new CommunitySpec;
126 4011 : comm->communities = attr->community()->communities();
127 4010 : update.path_attributes.push_back(comm);
128 : }
129 :
130 110978 : ExtCommunitySpec *ext_comm = new ExtCommunitySpec;
131 110979 : if (attr->ext_community() && attr->ext_community()->communities().size()) {
132 : const ExtCommunity::ExtCommunityList &v =
133 89295 : attr->ext_community()->communities();
134 89295 : for (ExtCommunity::ExtCommunityList::const_iterator it = v.begin();
135 1135150 : it != v.end(); ++it) {
136 1045834 : uint64_t value = get_value(it->data(), it->size());
137 1045835 : ext_comm->communities.push_back(value);
138 : }
139 : }
140 :
141 110981 : LargeCommunitySpec *large_comm = new LargeCommunitySpec;
142 110984 : 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 110984 : if (ext_comm->EncodeLength()) {
177 89301 : update.path_attributes.push_back(ext_comm);
178 : }
179 :
180 110988 : if (attr->origin_vn_path() && attr->origin_vn_path()->origin_vns().size()) {
181 746 : OriginVnPathSpec *ovnpath_spec = new OriginVnPathSpec;
182 : const OriginVnPath::OriginVnList &v =
183 746 : attr->origin_vn_path()->origin_vns();
184 746 : for (OriginVnPath::OriginVnList::const_iterator it = v.begin();
185 1492 : it != v.end(); ++it) {
186 746 : uint64_t value = get_value(it->data(), it->size());
187 746 : ovnpath_spec->origin_vns.push_back(value);
188 : }
189 746 : update.path_attributes.push_back(ovnpath_spec);
190 : }
191 :
192 110988 : 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 110988 : std::vector<uint8_t> nh;
199 :
200 110987 : route->BuildBgpProtoNextHop(nh, attr->nexthop());
201 :
202 : BgpMpNlri *nlri = new BgpMpNlri(
203 110980 : BgpAttribute::MPReachNlri, BgpAf::FamilyToAfi(family),
204 110980 : BgpAf::FamilyToSafi(family), nh);
205 110983 : update.path_attributes.push_back(nlri);
206 :
207 110980 : BgpProtoPrefix *prefix = new BgpProtoPrefix;
208 110982 : const uint32_t label = (family == Address::INET) ? 0 : roattr->label();
209 110982 : route->BuildProtoPrefix(prefix, attr, label, roattr->l3_label());
210 110977 : nlri->nlri.push_back(prefix);
211 :
212 110972 : int result = BgpProto::Encode(&update, data_, sizeof(data_),
213 110972 : &encode_offsets_, ribout->as4_supported());
214 110979 : 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 110867 : num_reach_route_++;
223 110867 : datalen_ = result;
224 110867 : return true;
225 110979 : }
226 :
227 45387 : bool BgpMessage::StartUnreach(const BgpRoute *route) {
228 45387 : BgpProto::Update update;
229 45386 : Address::Family family = table_->family();
230 :
231 : BgpMpNlri *nlri =
232 : new BgpMpNlri(BgpAttribute::MPUnreachNlri,
233 45386 : BgpAf::FamilyToAfi(family), BgpAf::FamilyToSafi(family));
234 45384 : update.path_attributes.push_back(nlri);
235 :
236 45380 : BgpProtoPrefix *prefix = new BgpProtoPrefix;
237 45379 : route->BuildProtoPrefix(prefix);
238 45371 : nlri->nlri.push_back(prefix);
239 :
240 : int result =
241 45371 : BgpProto::Encode(&update, data_, sizeof(data_), &encode_offsets_);
242 45386 : 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 45386 : num_unreach_route_++;
251 45386 : datalen_ = result;
252 45386 : return true;
253 45386 : }
254 :
255 156354 : void BgpMessage::Reset() {
256 156354 : Message::Reset();
257 156354 : table_ = NULL;
258 156354 : encode_offsets_.ClearOffsets();
259 156377 : datalen_ = 0;
260 156377 : }
261 :
262 156354 : bool BgpMessage::Start(const RibOut *ribout, bool cache_repr,
263 : const RibOutAttr *roattr, const BgpRoute *route) {
264 156354 : Reset();
265 156376 : table_ = ribout->table();
266 :
267 156375 : if (roattr->IsReachable()) {
268 110986 : return StartReach(ribout, roattr, route);
269 : } else {
270 45388 : return StartUnreach(route);
271 : }
272 : }
273 :
274 182808 : bool BgpMessage::UpdateLength(const char *tag, int size, int delta) {
275 182808 : int offset = encode_offsets_.FindOffset(tag);
276 182799 : if (offset < 0) {
277 0 : return false;
278 : }
279 182799 : int value = get_value(&data_[offset], size);
280 182799 : value += delta;
281 182799 : put_value(&data_[offset], size, value);
282 182800 : return true;
283 : }
284 :
285 60955 : bool BgpMessage::AddRoute(const BgpRoute *route, const RibOutAttr *roattr) {
286 60955 : uint8_t *data = data_ + datalen_;
287 60955 : size_t size = sizeof(data_) - datalen_;
288 60955 : Address::Family family = table_->family();
289 :
290 60955 : BgpMpNlri nlri;
291 60953 : nlri.afi = BgpAf::FamilyToAfi(family);
292 60953 : nlri.safi = BgpAf::FamilyToSafi(family);
293 60953 : BgpProtoPrefix *prefix = new BgpProtoPrefix;
294 60953 : if (roattr) {
295 60953 : const uint32_t label = (family == Address::INET) ? 0 : roattr->label();
296 60951 : route->BuildProtoPrefix(prefix, roattr->attr(), label);
297 : } else {
298 0 : route->BuildProtoPrefix(prefix);
299 : }
300 60952 : nlri.nlri.push_back(prefix);
301 :
302 60950 : int result = BgpProto::Encode(&nlri, data, size);
303 60954 : if (result <= 0) {
304 17 : return false;
305 : }
306 :
307 60937 : datalen_ += result;
308 60937 : if (roattr->IsReachable()) {
309 26576 : num_reach_route_++;
310 : } else {
311 34361 : num_unreach_route_++;
312 : }
313 :
314 60937 : if (!UpdateLength("BgpMsgLength", 2, result)) {
315 0 : assert(false);
316 : return false;
317 : }
318 :
319 60939 : if (!UpdateLength("BgpPathAttribute", 2, result)) {
320 0 : assert(false);
321 : return false;
322 : }
323 :
324 60938 : if (!UpdateLength("MpReachUnreachNlri", 2, result)) {
325 0 : assert(false);
326 : return false;
327 : }
328 :
329 60940 : return true;
330 60957 : }
331 :
332 156247 : void BgpMessage::Finish() {
333 156247 : }
334 :
335 168987 : const uint8_t *BgpMessage::GetData(IPeerUpdate *peer, size_t *lenp,
336 : const string **msg_str, string *temp) {
337 168987 : *lenp = datalen_;
338 168987 : 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 : }
|