Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/xmpp_message_builder.h"
6 :
7 : #include <boost/foreach.hpp>
8 :
9 : #include <algorithm>
10 :
11 : #include "bgp/ipeer.h"
12 : #include "bgp/bgp_server.h"
13 : #include "bgp/bgp_table.h"
14 : #include "bgp/extended-community/etree.h"
15 : #include "bgp/extended-community/mac_mobility.h"
16 : #include "bgp/ermvpn/ermvpn_route.h"
17 : #include "bgp/evpn/evpn_route.h"
18 : #include "bgp/mvpn/mvpn_route.h"
19 : #include "bgp/routing-instance/routing_instance.h"
20 : #include "bgp/security_group/security_group.h"
21 : #include "db/db.h"
22 : #include "net/community_type.h"
23 : #include "schema/xmpp_multicast_types.h"
24 : #include "schema/xmpp_mvpn_types.h"
25 : #include "schema/xmpp_enet_types.h"
26 : #include "xmpp/xmpp_init.h"
27 :
28 : using pugi::xml_attribute;
29 : using pugi::xml_document;
30 : using pugi::xml_node;
31 : using std::ostringstream;
32 : using std::copy;
33 : using std::fill;
34 : using std::string;
35 : using std::stringstream;
36 : using std::vector;
37 :
38 475815 : static inline const char *AfiName(uint16_t afi) {
39 475815 : switch (afi) {
40 265506 : case BgpAf::IPv4:
41 265506 : return "1";
42 : break;
43 200097 : case BgpAf::IPv6:
44 200097 : return "2";
45 : break;
46 10241 : case BgpAf::L2Vpn:
47 10241 : return "25";
48 : break;
49 : }
50 0 : assert(false);
51 : return NULL;
52 : }
53 :
54 475840 : static inline const char *XmppSafiName(uint8_t safi) {
55 475840 : switch (safi) {
56 456356 : case BgpAf::Unicast:
57 456356 : return "1";
58 : break;
59 6 : case BgpAf::Mpls:
60 6 : return "4";
61 : break;
62 6480 : case BgpAf::MVpn:
63 6480 : return "5";
64 : break;
65 2760 : case BgpAf::Mcast:
66 2760 : return "241";
67 : break;
68 10241 : case BgpAf::Enet:
69 10241 : return "242";
70 : break;
71 : }
72 0 : assert(false);
73 : return NULL;
74 : }
75 :
76 144 : BgpXmppMessage::BgpXmppMessage()
77 144 : : table_(NULL),
78 144 : writer_(XmlWriter(&repr_)),
79 144 : is_reachable_(false),
80 144 : cache_routes_(false),
81 144 : repr_valid_(false),
82 144 : mobility_(0, false),
83 288 : etree_leaf_(false) {
84 144 : msg_begin_.reserve(kMaxFromToLength);
85 144 : }
86 :
87 288 : BgpXmppMessage::~BgpXmppMessage() {
88 288 : }
89 :
90 475733 : void BgpXmppMessage::Reset() {
91 475733 : Message::Reset();
92 475736 : table_ = NULL;
93 475736 : is_reachable_ = false;
94 475736 : cache_routes_ = false;
95 475736 : repr_valid_ = false;
96 475736 : repr_.clear();
97 475719 : }
98 :
99 475731 : bool BgpXmppMessage::Start(const RibOut *ribout, bool cache_routes,
100 : const RibOutAttr *roattr, const BgpRoute *route) {
101 475731 : Reset();
102 475724 : table_ = ribout->table();
103 475720 : is_reachable_ = roattr->IsReachable();
104 475711 : cache_routes_ = cache_routes;
105 475711 : Address::Family family = table_->family();
106 :
107 475714 : if (is_reachable_) {
108 316066 : const BgpAttr *attr = roattr->attr();
109 316058 : ProcessCommunity(attr->community());
110 316046 : ProcessExtCommunity(attr->ext_community());
111 : }
112 :
113 : // Reserve space for the begin line that contains the message opening tag
114 : // with from and to attributes. Actual value gets patched in when GetData
115 : // is called.
116 475763 : repr_.append(kMaxFromToLength, ' ');
117 :
118 : // Add opening tags for event and items. The closing tags are added when
119 : // GetData is called.
120 475766 : repr_ += "\n\t<event xmlns=\"http://jabber.org/protocol/pubsub\">";
121 475795 : repr_ += "\n\t\t<items node=\"";
122 475820 : repr_ += AfiName(BgpAf::FamilyToAfi(family));
123 475832 : repr_ += "/";
124 475858 : repr_ += XmppSafiName(BgpAf::FamilyToXmppSafi(family));
125 475830 : repr_ += "/";
126 475836 : repr_ += table_->routing_instance()->name();
127 475830 : repr_ += "\">\n";
128 :
129 475832 : if (table_->family() == Address::ERMVPN) {
130 2760 : AddMcastRoute(route, roattr);
131 473068 : } else if (table_->family() == Address::EVPN) {
132 10241 : AddEnetRoute(route, roattr);
133 462821 : } else if (table_->family() == Address::INET6) {
134 200087 : AddInet6Route(route, roattr);
135 262735 : } else if (table_->family() == Address::MVPN) {
136 6480 : AddMvpnRoute(route, roattr);
137 : } else {
138 256267 : AddInetRoute(route, roattr);
139 : }
140 475870 : return true;
141 : }
142 :
143 475871 : void BgpXmppMessage::Finish() {
144 475871 : }
145 :
146 613275 : bool BgpXmppMessage::AddRoute(const BgpRoute *route, const RibOutAttr *roattr) {
147 613275 : assert(is_reachable_ == roattr->IsReachable());
148 613299 : if (is_reachable_ && num_reach_route_ >= kMaxReachCount)
149 241 : return false;
150 613058 : if (!is_reachable_ && num_unreach_route_ >= kMaxUnreachCount)
151 7 : return false;
152 :
153 613051 : if (is_reachable_) {
154 520915 : const BgpAttr *attr = roattr->attr();
155 520909 : ProcessCommunity(attr->community());
156 520908 : ProcessExtCommunity(attr->ext_community());
157 : }
158 :
159 613055 : if (table_->family() == Address::ERMVPN) {
160 134 : return AddMcastRoute(route, roattr);
161 612915 : } else if (table_->family() == Address::EVPN) {
162 2186 : return AddEnetRoute(route, roattr);
163 610727 : } else if (table_->family() == Address::INET6) {
164 120360 : return AddInet6Route(route, roattr);
165 490366 : } else if (table_->family() == Address::MVPN) {
166 190464 : return AddMvpnRoute(route, roattr);
167 : } else {
168 299938 : return AddInetRoute(route, roattr);
169 : }
170 : }
171 :
172 531353 : void BgpXmppMessage::EncodeNextHop(const BgpRoute *route,
173 : const RibOutAttr::NextHop &nexthop,
174 : autogen::ItemType *item) {
175 531353 : autogen::NextHopType item_nexthop;
176 :
177 531338 : const IpAddress &address = nexthop.address();
178 531340 : if (address.is_v4()) {
179 528002 : item_nexthop.af = BgpAf::IPv4;
180 528002 : item_nexthop.address = address.to_v4().to_string();
181 : } else {
182 3338 : item_nexthop.af = BgpAf::IPv6;
183 3338 : item_nexthop.address = address.to_v6().to_string();
184 : }
185 531576 : item_nexthop.label = nexthop.label();
186 531559 : item_nexthop.virtual_network = GetVirtualNetwork(nexthop);
187 531566 : item_nexthop.tag_list.tag = nexthop.tag_list();
188 531390 : item_nexthop.is_new_tags_list = true;
189 :
190 : // If there's a non-zero label and encap list is empty use mpls over gre
191 : // as default encap.
192 531390 : if (item_nexthop.label) {
193 522414 : vector<string> &encap_list =
194 : item_nexthop.tunnel_encapsulation_list.tunnel_encapsulation;
195 522414 : if (nexthop.encap().empty()) {
196 100620 : encap_list.push_back(string("gre"));
197 : } else {
198 421781 : encap_list = nexthop.encap();
199 : }
200 : }
201 :
202 531326 : item->entry.next_hops.next_hop.push_back(item_nexthop);
203 531353 : }
204 :
205 627331 : void BgpXmppMessage::AddIpReach(const BgpRoute *route,
206 : const RibOutAttr *roattr) {
207 627331 : if (!roattr->repr().empty()) {
208 98208 : repr_ += roattr->repr();
209 98208 : return;
210 : }
211 529133 : Address::Family family = table_->family();
212 :
213 529129 : autogen::ItemType item;
214 529101 : item.entry.nlri.af = BgpAf::FamilyToAfi(family);
215 529102 : item.entry.nlri.safi = BgpAf::FamilyToXmppSafi(family);
216 529095 : item.entry.nlri.address = route->ToString();
217 529185 : item.entry.version = 1;
218 529185 : item.entry.virtual_network = GetVirtualNetwork(route, roattr);
219 529201 : item.entry.local_preference = roattr->attr()->local_pref();
220 529174 : item.entry.med = roattr->attr()->med();
221 529145 : item.entry.sequence_number = mobility_.sequence_number;
222 529145 : item.entry.mobility.seqno = mobility_.sequence_number;
223 529145 : item.entry.mobility.sticky = mobility_.sticky;
224 :
225 529145 : assert(!roattr->nexthop_list().empty());
226 :
227 : // Encode all next-hops in the list.
228 1591886 : BOOST_FOREACH(const RibOutAttr::NextHop &nexthop, roattr->nexthop_list()) {
229 531352 : EncodeNextHop(route, nexthop, &item);
230 : }
231 :
232 529080 : for (vector<int>::const_iterator it = security_group_list_.begin();
233 852031 : it != security_group_list_.end(); ++it) {
234 323009 : item.entry.security_group_list.security_group.push_back(*it);
235 : }
236 :
237 529009 : for (vector<string>::const_iterator it = community_list_.begin();
238 541119 : it != community_list_.end(); ++it) {
239 12123 : item.entry.community_tag_list.community_tag.push_back(*it);
240 : }
241 :
242 : // Encode load balance attribute.
243 528996 : if (!load_balance_attribute_.IsDefault())
244 4 : load_balance_attribute_.Encode(&item.entry.load_balance);
245 :
246 528991 : xml_node node = doc_.append_child("item");
247 528927 : node.append_attribute("id") = route->ToXmppIdString().c_str();
248 :
249 : // Remember the previous size.
250 : // Using remove_child instead of reset allows memory pages allocated for
251 : // the xml_document to be reused during the lifetime of the xml_document.
252 529031 : size_t pos = repr_.size();
253 529028 : item.Encode(&node);
254 528974 : doc_.print(writer_, "\t", pugi::format_default, pugi::encoding_auto, 3);
255 529164 : doc_.remove_child(node);
256 :
257 : // Cache the substring starting at the previous size.
258 529129 : if (cache_routes_)
259 29208 : roattr->set_repr(repr_, pos);
260 529132 : }
261 :
262 249248 : void BgpXmppMessage::AddIpUnreach(const BgpRoute *route) {
263 249248 : repr_ += "\t\t\t<retract id=\"" + route->ToXmppIdString() + "\" />\n";
264 249357 : }
265 :
266 556199 : bool BgpXmppMessage::AddInetRoute(const BgpRoute *route,
267 : const RibOutAttr *roattr) {
268 556199 : if (is_reachable_) {
269 424718 : num_reach_route_++;
270 424718 : AddIpReach(route, roattr);
271 : } else {
272 131481 : num_unreach_route_++;
273 131481 : AddIpUnreach(route);
274 : }
275 556241 : return true;
276 : }
277 :
278 320445 : bool BgpXmppMessage::AddInet6Route(const BgpRoute *route,
279 : const RibOutAttr *roattr) {
280 320445 : if (is_reachable_) {
281 202652 : num_reach_route_++;
282 202652 : AddIpReach(route, roattr);
283 : } else {
284 117793 : num_unreach_route_++;
285 117793 : AddIpUnreach(route);
286 : }
287 320480 : return true;
288 : }
289 :
290 9052 : void BgpXmppMessage::EncodeEnetNextHop(const BgpRoute *route,
291 : const RibOutAttr::NextHop &nexthop,
292 : autogen::EnetItemType *item) {
293 9052 : autogen::EnetNextHopType item_nexthop;
294 :
295 9052 : item_nexthop.af = BgpAf::IPv4;
296 9052 : item_nexthop.address = nexthop.address().to_v4().to_string();
297 9052 : item_nexthop.label = nexthop.label();
298 9052 : item_nexthop.l3_label = nexthop.l3_label();
299 9052 : if (!nexthop.mac().IsZero())
300 20 : item_nexthop.mac = nexthop.mac().ToString();
301 :
302 : // If encap list is empty use mpls over gre as default encap.
303 9052 : vector<string> &encap_list =
304 : item_nexthop.tunnel_encapsulation_list.tunnel_encapsulation;
305 9052 : if (nexthop.encap().empty()) {
306 0 : encap_list.push_back(string("gre"));
307 : } else {
308 9052 : encap_list = nexthop.encap();
309 : }
310 9052 : item_nexthop.tag_list.tag = nexthop.tag_list();
311 9052 : item_nexthop.is_new_tags_list = true;
312 9052 : item->entry.next_hops.next_hop.push_back(item_nexthop);
313 9052 : }
314 :
315 10435 : void BgpXmppMessage::AddEnetReach(const BgpRoute *route,
316 : const RibOutAttr *roattr) {
317 10435 : if (!roattr->repr().empty()) {
318 0 : repr_ += roattr->repr();
319 0 : return;
320 : }
321 10435 : Address::Family family = table_->family();
322 :
323 10435 : autogen::EnetItemType item;
324 10435 : item.entry.nlri.af = BgpAf::FamilyToAfi(family);
325 10435 : item.entry.nlri.safi = BgpAf::FamilyToXmppSafi(family);
326 :
327 10435 : EvpnRoute *evpn_route =
328 : static_cast<EvpnRoute *>(const_cast<BgpRoute *>(route));
329 10435 : const EvpnPrefix &evpn_prefix = evpn_route->GetPrefix();
330 10435 : item.entry.nlri.ethernet_tag = evpn_prefix.tag();
331 10435 : item.entry.nlri.mac = evpn_prefix.mac_addr().ToString();
332 20870 : item.entry.nlri.address = evpn_prefix.ip_address().to_string() + "/" +
333 31305 : integerToString(evpn_prefix.ip_address_length());
334 10435 : item.entry.nlri.source = evpn_prefix.source().to_string();
335 10435 : item.entry.nlri.group = evpn_prefix.group().to_string();
336 :
337 10435 : item.entry.virtual_network = GetVirtualNetwork(route, roattr);
338 10435 : item.entry.local_preference = roattr->attr()->local_pref();
339 10435 : item.entry.med = roattr->attr()->med();
340 10435 : item.entry.sequence_number = mobility_.sequence_number;
341 10435 : item.entry.mobility.seqno = mobility_.sequence_number;
342 10435 : item.entry.mobility.sticky = mobility_.sticky;
343 10435 : item.entry.etree_leaf = etree_leaf_;
344 :
345 10435 : for (vector<int>::const_iterator it = security_group_list_.begin();
346 20878 : it != security_group_list_.end(); ++it) {
347 10443 : item.entry.security_group_list.security_group.push_back(*it);
348 : }
349 :
350 10435 : const BgpOList *olist = roattr->attr()->olist().get();
351 10435 : assert((olist == NULL) != roattr->nexthop_list().empty());
352 :
353 10435 : if (olist) {
354 1511 : assert(olist->olist().subcode == BgpAttribute::OList);
355 14073 : BOOST_FOREACH(const BgpOListElem *elem, olist->elements()) {
356 6281 : autogen::EnetNextHopType nh;
357 6281 : nh.af = BgpAf::IPv4;
358 6281 : nh.address = elem->address.to_string();
359 6281 : nh.label = elem->label;
360 6281 : nh.tunnel_encapsulation_list.tunnel_encapsulation = elem->encap;
361 6281 : item.entry.olist.next_hop.push_back(nh);
362 6281 : }
363 : }
364 :
365 10435 : const BgpOList *leaf_olist = roattr->attr()->leaf_olist().get();
366 10435 : assert((leaf_olist == NULL) != roattr->nexthop_list().empty());
367 :
368 10435 : if (leaf_olist) {
369 1511 : assert(leaf_olist->olist().subcode == BgpAttribute::LeafOList);
370 1511 : BOOST_FOREACH(const BgpOListElem *elem, leaf_olist->elements()) {
371 0 : autogen::EnetNextHopType nh;
372 0 : nh.af = BgpAf::IPv4;
373 0 : nh.address = elem->address.to_string();
374 0 : nh.label = elem->label;
375 0 : nh.tunnel_encapsulation_list.tunnel_encapsulation = elem->encap;
376 0 : item.entry.leaf_olist.next_hop.push_back(nh);
377 0 : }
378 : }
379 :
380 28539 : BOOST_FOREACH(const RibOutAttr::NextHop &nexthop, roattr->nexthop_list()) {
381 9052 : EncodeEnetNextHop(route, nexthop, &item);
382 : }
383 :
384 11357 : for (const auto &peer_name : route->peer_sources()) {
385 922 : item.entry.peers.peer.push_back(peer_name);
386 : }
387 :
388 10435 : xml_node node = doc_.append_child("item");
389 10435 : node.append_attribute("id") = route->ToXmppIdString().c_str();
390 :
391 : // Remember the previous size.
392 : // Using remove_child instead of reset allows memory pages allocated for
393 : // the xml_document to be reused during the lifetime of the xml_document.
394 10435 : size_t pos = repr_.size();
395 10435 : item.Encode(&node);
396 10435 : doc_.print(writer_, "\t", pugi::format_default, pugi::encoding_auto, 3);
397 10435 : doc_.remove_child(node);
398 :
399 : // Cache the substring starting at the previous size.
400 10435 : if (cache_routes_)
401 2026 : roattr->set_repr(repr_, pos);
402 10435 : }
403 :
404 1992 : void BgpXmppMessage::AddEnetUnreach(const BgpRoute *route) {
405 1992 : repr_ += "\t\t\t<retract id=\"" + route->ToXmppIdString() + "\" />\n";
406 1992 : }
407 :
408 12427 : bool BgpXmppMessage::AddEnetRoute(const BgpRoute *route,
409 : const RibOutAttr *roattr) {
410 12427 : if (is_reachable_) {
411 10435 : num_reach_route_++;
412 10435 : AddEnetReach(route, roattr);
413 : } else {
414 1992 : num_unreach_route_++;
415 1992 : AddEnetUnreach(route);
416 : }
417 12427 : return true;
418 : }
419 :
420 : //
421 : // Note that there's no need to cache the string representation since a given
422 : // mcast route is sent to exactly one xmpp peer.
423 : //
424 2431 : void BgpXmppMessage::AddMcastReach(const BgpRoute *route,
425 : const RibOutAttr *roattr) {
426 2431 : Address::Family family = table_->family();
427 2431 : autogen::McastItemType item;
428 2431 : item.entry.nlri.af = BgpAf::FamilyToAfi(family);
429 2431 : item.entry.nlri.safi = BgpAf::FamilyToXmppSafi(family);
430 :
431 2431 : ErmVpnRoute *ermvpn_route =
432 : static_cast<ErmVpnRoute *>(const_cast<BgpRoute *>(route));
433 2431 : item.entry.nlri.group = ermvpn_route->GetPrefix().group().to_string();
434 2431 : item.entry.nlri.source = ermvpn_route->GetPrefix().source().to_string();
435 2431 : item.entry.nlri.source_label = roattr->label();
436 2431 : if (!roattr->source_address().is_unspecified()) {
437 : item.entry.nlri.source_address =
438 147 : roattr->source_address().to_string();
439 : }
440 :
441 2431 : const BgpOList *olist = roattr->attr()->olist().get();
442 2431 : assert(olist->olist().subcode == BgpAttribute::OList);
443 7637 : BOOST_FOREACH(const BgpOListElem *elem, olist->elements()) {
444 2603 : autogen::McastNextHopType nh;
445 2603 : nh.af = BgpAf::IPv4;
446 2603 : nh.address = elem->address.to_string();
447 2603 : nh.label = integerToString(elem->label);
448 2603 : nh.tunnel_encapsulation_list.tunnel_encapsulation = elem->encap;
449 2603 : item.entry.olist.next_hop.push_back(nh);
450 2603 : }
451 :
452 : // Using remove_child instead of reset allows memory pages allocated for
453 : // the xml_document to be reused during the lifetime of the xml_document.
454 2431 : xml_node node = doc_.append_child("item");
455 2431 : node.append_attribute("id") = route->ToXmppIdString().c_str();
456 2431 : item.Encode(&node);
457 2431 : doc_.print(writer_, "\t", pugi::format_default, pugi::encoding_auto, 3);
458 2431 : doc_.remove_child(node);
459 2431 : }
460 :
461 463 : void BgpXmppMessage::AddMcastUnreach(const BgpRoute *route) {
462 463 : repr_ += "\t\t\t<retract id=\"" + route->ToXmppIdString() + "\" />\n";
463 463 : }
464 :
465 2894 : bool BgpXmppMessage::AddMcastRoute(const BgpRoute *route,
466 : const RibOutAttr *roattr) {
467 2894 : if (is_reachable_) {
468 2431 : num_reach_route_++;
469 2431 : AddMcastReach(route, roattr);
470 : } else {
471 463 : num_unreach_route_++;
472 463 : AddMcastUnreach(route);
473 : }
474 2894 : return true;
475 : }
476 :
477 196821 : void BgpXmppMessage::AddMvpnReach(const BgpRoute *route,
478 : const RibOutAttr *roattr) {
479 196821 : Address::Family family = table_->family();
480 196821 : autogen::MvpnItemType item;
481 196821 : item.entry.nlri.af = BgpAf::FamilyToAfi(family);
482 196821 : item.entry.nlri.safi = BgpAf::FamilyToXmppSafi(family);
483 :
484 196821 : MvpnRoute *mvpn_route =
485 : static_cast<MvpnRoute *>(const_cast<BgpRoute *>(route));
486 196821 : item.entry.nlri.group = mvpn_route->GetPrefix().group().to_string();
487 196821 : item.entry.nlri.source = mvpn_route->GetPrefix().source().to_string();
488 196821 : item.entry.nlri.route_type = mvpn_route->GetPrefix().type();
489 196821 : assert((item.entry.nlri.route_type == MvpnPrefix::SourceActiveADRoute) ||
490 : (item.entry.nlri.route_type == MvpnPrefix::SourceTreeJoinRoute));
491 :
492 196821 : if (item.entry.nlri.route_type == MvpnPrefix::SourceActiveADRoute) {
493 196724 : const BgpOList *olist = roattr->attr()->olist().get();
494 196724 : assert(olist->olist().subcode == BgpAttribute::OList);
495 590172 : BOOST_FOREACH(const BgpOListElem *elem, olist->elements()) {
496 196724 : autogen::MvpnNextHopType nh;
497 196724 : nh.af = BgpAf::IPv4;
498 196724 : nh.address = elem->address.to_string();
499 196724 : nh.label = elem->label;
500 196724 : nh.tunnel_encapsulation_list.tunnel_encapsulation = elem->encap;
501 196724 : item.entry.olist.next_hop.push_back(nh);
502 196724 : }
503 : }
504 :
505 : // Using remove_child instead of reset allows memory pages allocated for
506 : // the xml_document to be reused during the lifetime of the xml_document.
507 196821 : xml_node node = doc_.append_child("item");
508 196821 : node.append_attribute("id") = route->ToXmppIdString().c_str();
509 196821 : item.Encode(&node);
510 196821 : doc_.print(writer_, "\t", pugi::format_default, pugi::encoding_auto, 3);
511 196821 : doc_.remove_child(node);
512 196821 : }
513 :
514 123 : void BgpXmppMessage::AddMvpnUnreach(const BgpRoute *route) {
515 123 : repr_ += "\t\t\t<retract id=\"" + route->ToXmppIdString() + "\" />\n";
516 123 : }
517 :
518 196944 : bool BgpXmppMessage::AddMvpnRoute(const BgpRoute *route,
519 : const RibOutAttr *roattr) {
520 196944 : if (is_reachable_) {
521 196821 : num_reach_route_++;
522 196821 : AddMvpnReach(route, roattr);
523 : } else {
524 123 : num_unreach_route_++;
525 123 : AddMvpnUnreach(route);
526 : }
527 196944 : return true;
528 : }
529 :
530 14181975 : const uint8_t *BgpXmppMessage::GetData(IPeerUpdate *peer, size_t *lenp,
531 : const string **msg_str, string *temp) {
532 : // Build begin line that contains message opening tag with from and to
533 : // attributes.
534 14181975 : msg_begin_.clear();
535 14182165 : msg_begin_ += "\n<message from=\"";
536 14182225 : msg_begin_ += XmppInit::kControlNodeJID;
537 14182305 : msg_begin_ += "\" to=\"";
538 14182365 : msg_begin_ += peer->ToString();
539 14182429 : msg_begin_ += "/";
540 14182440 : msg_begin_ += XmppInit::kBgpPeer;
541 14182396 : msg_begin_ += "\">";
542 :
543 : // Add closing tags if this is the first peer to which the message will
544 : // be sent.
545 14182408 : if (!repr_valid_) {
546 475908 : repr_ += "\t\t</items>\n\t</event>\n</message>\n";
547 475903 : repr_valid_ = true;
548 : }
549 :
550 : // Replace the begin line if it fits in the space reserved at the start
551 : // of repr_. Use fill and copy instead of string::replace as the latter
552 : // seems to construct a new temporary string to hold the input data to
553 : // be copied.
554 : // Otherwise build a new string with the begin line and the rest of the
555 : // message in repr_.
556 14182403 : size_t begin_size = msg_begin_.size();
557 14182292 : if (begin_size <= kMaxFromToLength) {
558 9988062 : size_t extra = kMaxFromToLength - begin_size;
559 9988062 : char *data = const_cast<char *>(repr_.c_str());
560 9988073 : fill(data, data + extra, ' ');
561 9988076 : copy(msg_begin_.c_str(), msg_begin_.c_str() + begin_size, data + extra);
562 9987863 : *lenp = repr_.size() - extra;
563 9987848 : *msg_str = &repr_;
564 9987848 : return reinterpret_cast<const uint8_t *>(repr_.c_str()) + extra;
565 : } else {
566 4194230 : *temp = msg_begin_ + string(repr_, kMaxFromToLength);
567 4194304 : *lenp = temp->size();
568 4194304 : *msg_str = NULL;
569 4194304 : return reinterpret_cast<const uint8_t *>(temp->c_str());
570 : }
571 : }
572 :
573 836953 : void BgpXmppMessage::ProcessCommunity(const Community *community) {
574 836953 : community_list_.clear();
575 836955 : if (community == NULL)
576 824852 : return;
577 36355 : BOOST_FOREACH(uint32_t value, community->communities()) {
578 12128 : community_list_.push_back(CommunityType::CommunityToString(value));
579 : }
580 : }
581 :
582 836943 : void BgpXmppMessage::ProcessExtCommunity(const ExtCommunity *ext_community) {
583 836943 : mobility_.sequence_number = 0;
584 836943 : mobility_.sticky = false;
585 836943 : etree_leaf_ = false;
586 836943 : security_group_list_.clear();
587 836949 : load_balance_attribute_ = LoadBalance::LoadBalanceAttribute();
588 837141 : if (ext_community == NULL)
589 208123 : return;
590 :
591 629018 : as_t as_number = table_->server()->autonomous_system();
592 628987 : bool sg_asn_match = true;
593 628963 : for (ExtCommunity::ExtCommunityList::const_iterator iter =
594 628987 : ext_community->communities().begin();
595 3676316 : iter != ext_community->communities().end(); ++iter) {
596 3047333 : if (ExtCommunity::is_security_group(*iter)) {
597 431787 : SecurityGroup sg(*iter);
598 431796 : if (as_number <= AS2_MAX)
599 235188 : if (sg.as_number() != as_number && !sg.IsGlobal())
600 2 : continue;
601 431799 : security_group_list_.push_back(sg.security_group_id());
602 2615713 : } else if (ExtCommunity::is_security_group4(*iter)) {
603 196608 : SecurityGroup4ByteAs sg(*iter);
604 196608 : if (sg.as_number() != as_number)
605 0 : sg_asn_match = false;
606 2419092 : } else if (ExtCommunity::is_mac_mobility(*iter)) {
607 1079 : MacMobility mm(*iter);
608 1079 : mobility_.sequence_number = mm.sequence_number();
609 1079 : mobility_.sticky = mm.sticky();
610 2417985 : } else if (ExtCommunity::is_load_balance(*iter)) {
611 4 : LoadBalance load_balance(*iter);
612 4 : load_balance.FillAttribute(&load_balance_attribute_);
613 2417929 : } else if (ExtCommunity::is_etree(*iter)) {
614 9289 : ETree etree(*iter);
615 9289 : etree_leaf_ = etree.leaf();
616 : }
617 : }
618 628883 : if (!sg_asn_match)
619 0 : security_group_list_.clear();
620 : }
621 :
622 1069548 : string BgpXmppMessage::GetVirtualNetwork(
623 : const RibOutAttr::NextHop &nexthop) const {
624 1069548 : int index = nexthop.origin_vn_index();
625 1069536 : if (index > 0) {
626 : const RoutingInstanceMgr *manager =
627 69481 : table_->routing_instance()->manager();
628 69481 : return manager->GetVirtualNetworkByVnIndex(index);
629 1000055 : } else if (index == 0) {
630 61348 : return table_->routing_instance()->GetVirtualNetworkName();
631 : } else {
632 938707 : return "unresolved";
633 : }
634 : }
635 :
636 539613 : string BgpXmppMessage::GetVirtualNetwork(const BgpRoute *route,
637 : const RibOutAttr *roattr) const {
638 539613 : if (!is_reachable_) {
639 0 : return "unresolved";
640 539613 : } else if (roattr->nexthop_list().empty()) {
641 1511 : if (roattr->vrf_originated()) {
642 1511 : return table_->routing_instance()->GetVirtualNetworkName();
643 : } else {
644 0 : return "unresolved";
645 : }
646 : } else {
647 538048 : return GetVirtualNetwork(roattr->nexthop_list().front());
648 : }
649 : }
650 :
651 50 : BgpXmppMessageBuilder::BgpXmppMessageBuilder() {
652 50 : }
653 :
654 144 : Message *BgpXmppMessageBuilder::Create() const {
655 144 : return new BgpXmppMessage;
656 : }
|