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/xmpp_message_builder.h"
7 :
8 : #include <boost/foreach.hpp>
9 :
10 : #include <algorithm>
11 :
12 : #include "bgp/ipeer.h"
13 : #include "bgp/bgp_server.h"
14 : #include "bgp/bgp_table.h"
15 : #include "bgp/extended-community/etree.h"
16 : #include "bgp/extended-community/mac_mobility.h"
17 : #include "bgp/ermvpn/ermvpn_route.h"
18 : #include "bgp/evpn/evpn_route.h"
19 : #include "bgp/mvpn/mvpn_route.h"
20 : #include "bgp/routing-instance/routing_instance.h"
21 : #include "bgp/security_group/security_group.h"
22 : #include "db/db.h"
23 : #include "net/community_type.h"
24 : #include "schema/xmpp_multicast_types.h"
25 : #include "schema/xmpp_mvpn_types.h"
26 : #include "schema/xmpp_enet_types.h"
27 : #include "xmpp/xmpp_init.h"
28 :
29 : using pugi::xml_attribute;
30 : using pugi::xml_document;
31 : using pugi::xml_node;
32 : using std::ostringstream;
33 : using std::copy;
34 : using std::fill;
35 : using std::string;
36 : using std::stringstream;
37 : using std::vector;
38 :
39 468473 : static inline const char *AfiName(uint16_t afi) {
40 468473 : switch (afi) {
41 263996 : case BgpAf::IPv4:
42 263996 : return "1";
43 : break;
44 194127 : case BgpAf::IPv6:
45 194127 : return "2";
46 : break;
47 10397 : case BgpAf::L2Vpn:
48 10397 : return "25";
49 : break;
50 : }
51 0 : assert(false);
52 : return NULL;
53 : }
54 :
55 468500 : static inline const char *XmppSafiName(uint8_t safi) {
56 468500 : switch (safi) {
57 448932 : case BgpAf::Unicast:
58 448932 : return "1";
59 : break;
60 11 : case BgpAf::Mpls:
61 11 : return "4";
62 : break;
63 6475 : case BgpAf::MVpn:
64 6475 : return "5";
65 : break;
66 2700 : case BgpAf::Mcast:
67 2700 : return "241";
68 : break;
69 10397 : case BgpAf::Enet:
70 10397 : return "242";
71 : break;
72 : }
73 0 : assert(false);
74 : return NULL;
75 : }
76 :
77 144 : BgpXmppMessage::BgpXmppMessage()
78 144 : : table_(NULL),
79 144 : writer_(XmlWriter(&repr_)),
80 144 : is_reachable_(false),
81 144 : cache_routes_(false),
82 144 : repr_valid_(false),
83 144 : mobility_(0, false),
84 288 : etree_leaf_(false) {
85 144 : msg_begin_.reserve(kMaxFromToLength);
86 144 : }
87 :
88 288 : BgpXmppMessage::~BgpXmppMessage() {
89 288 : }
90 :
91 468415 : void BgpXmppMessage::Reset() {
92 468415 : Message::Reset();
93 468415 : table_ = NULL;
94 468415 : is_reachable_ = false;
95 468415 : cache_routes_ = false;
96 468415 : repr_valid_ = false;
97 468415 : repr_.clear();
98 468416 : }
99 :
100 468408 : bool BgpXmppMessage::Start(const RibOut *ribout, bool cache_routes,
101 : const RibOutAttr *roattr, const BgpRoute *route) {
102 468408 : Reset();
103 468413 : table_ = ribout->table();
104 468417 : is_reachable_ = roattr->IsReachable();
105 468403 : cache_routes_ = cache_routes;
106 468403 : Address::Family family = table_->family();
107 :
108 468398 : if (is_reachable_) {
109 318315 : const BgpAttr *attr = roattr->attr();
110 318315 : ProcessCommunity(attr->community());
111 318295 : ProcessExtCommunity(attr->ext_community());
112 : }
113 :
114 : // Reserve space for the begin line that contains the message opening tag
115 : // with from and to attributes. Actual value gets patched in when GetData
116 : // is called.
117 468422 : repr_.append(kMaxFromToLength, ' ');
118 :
119 : // Add opening tags for event and items. The closing tags are added when
120 : // GetData is called.
121 468419 : repr_ += "\n\t<event xmlns=\"http://jabber.org/protocol/pubsub\">";
122 468458 : repr_ += "\n\t\t<items node=\"";
123 468486 : repr_ += AfiName(BgpAf::FamilyToAfi(family));
124 468515 : repr_ += "/";
125 468533 : repr_ += XmppSafiName(BgpAf::FamilyToXmppSafi(family));
126 468506 : repr_ += "/";
127 468508 : repr_ += table_->routing_instance()->name();
128 468503 : repr_ += "\">\n";
129 :
130 468514 : if (table_->family() == Address::ERMVPN) {
131 2700 : AddMcastRoute(route, roattr);
132 465807 : } else if (table_->family() == Address::EVPN) {
133 10397 : AddEnetRoute(route, roattr);
134 455397 : } else if (table_->family() == Address::INET6) {
135 194124 : AddInet6Route(route, roattr);
136 261264 : } else if (table_->family() == Address::MVPN) {
137 6475 : AddMvpnRoute(route, roattr);
138 : } else {
139 254793 : AddInetRoute(route, roattr);
140 : }
141 468530 : return true;
142 : }
143 :
144 468526 : void BgpXmppMessage::Finish() {
145 468526 : }
146 :
147 621298 : bool BgpXmppMessage::AddRoute(const BgpRoute *route, const RibOutAttr *roattr) {
148 621298 : assert(is_reachable_ == roattr->IsReachable());
149 621296 : if (is_reachable_ && num_reach_route_ >= kMaxReachCount)
150 184 : return false;
151 621112 : if (!is_reachable_ && num_unreach_route_ >= kMaxUnreachCount)
152 8 : return false;
153 :
154 621104 : if (is_reachable_) {
155 518598 : const BgpAttr *attr = roattr->attr();
156 518592 : ProcessCommunity(attr->community());
157 518592 : ProcessExtCommunity(attr->ext_community());
158 : }
159 :
160 621118 : if (table_->family() == Address::ERMVPN) {
161 103 : return AddMcastRoute(route, roattr);
162 621011 : } else if (table_->family() == Address::EVPN) {
163 2114 : return AddEnetRoute(route, roattr);
164 618895 : } else if (table_->family() == Address::INET6) {
165 126616 : return AddInet6Route(route, roattr);
166 492280 : } else if (table_->family() == Address::MVPN) {
167 190464 : return AddMvpnRoute(route, roattr);
168 : } else {
169 301851 : return AddInetRoute(route, roattr);
170 : }
171 : }
172 :
173 531240 : void BgpXmppMessage::EncodeNextHop(const BgpRoute *route,
174 : const RibOutAttr::NextHop &nexthop,
175 : autogen::ItemType *item) {
176 531240 : autogen::NextHopType item_nexthop;
177 :
178 531240 : const IpAddress &address = nexthop.address();
179 531234 : if (address.is_v4()) {
180 527942 : item_nexthop.af = BgpAf::IPv4;
181 527942 : item_nexthop.address = address.to_v4().to_string();
182 : } else {
183 3283 : item_nexthop.af = BgpAf::IPv6;
184 3283 : item_nexthop.address = address.to_v6().to_string();
185 : }
186 531540 : item_nexthop.label = nexthop.label();
187 531523 : item_nexthop.virtual_network = GetVirtualNetwork(nexthop);
188 531525 : item_nexthop.tag_list.tag = nexthop.tag_list();
189 531352 : item_nexthop.is_new_tags_list = true;
190 :
191 : // If there's a non-zero label and encap list is empty use mpls over gre
192 : // as default encap.
193 531352 : if (item_nexthop.label) {
194 522408 : vector<string> &encap_list =
195 : item_nexthop.tunnel_encapsulation_list.tunnel_encapsulation;
196 522408 : if (nexthop.encap().empty()) {
197 100567 : encap_list.push_back(string("gre"));
198 : } else {
199 421829 : encap_list = nexthop.encap();
200 : }
201 : }
202 :
203 531294 : item->entry.next_hops.next_hop.push_back(item_nexthop);
204 531358 : }
205 :
206 627313 : void BgpXmppMessage::AddIpReach(const BgpRoute *route,
207 : const RibOutAttr *roattr) {
208 627313 : if (!roattr->repr().empty()) {
209 98208 : repr_ += roattr->repr();
210 98208 : return;
211 : }
212 529110 : Address::Family family = table_->family();
213 :
214 529110 : autogen::ItemType item;
215 529060 : item.entry.nlri.af = BgpAf::FamilyToAfi(family);
216 529055 : item.entry.nlri.safi = BgpAf::FamilyToXmppSafi(family);
217 529059 : item.entry.nlri.address = route->ToString();
218 529141 : item.entry.version = 1;
219 529141 : item.entry.virtual_network = GetVirtualNetwork(route, roattr);
220 529140 : item.entry.local_preference = roattr->attr()->local_pref();
221 529099 : item.entry.med = roattr->attr()->med();
222 529076 : item.entry.sequence_number = mobility_.sequence_number;
223 529076 : item.entry.mobility.seqno = mobility_.sequence_number;
224 529076 : item.entry.mobility.sticky = mobility_.sticky;
225 :
226 529076 : assert(!roattr->nexthop_list().empty());
227 :
228 : // Encode all next-hops in the list.
229 1591653 : BOOST_FOREACH(const RibOutAttr::NextHop &nexthop, roattr->nexthop_list()) {
230 531261 : EncodeNextHop(route, nexthop, &item);
231 : }
232 :
233 529026 : for (vector<int>::const_iterator it = security_group_list_.begin();
234 851981 : it != security_group_list_.end(); ++it) {
235 322988 : item.entry.security_group_list.security_group.push_back(*it);
236 : }
237 :
238 528977 : for (vector<string>::const_iterator it = community_list_.begin();
239 540798 : it != community_list_.end(); ++it) {
240 11830 : item.entry.community_tag_list.community_tag.push_back(*it);
241 : }
242 :
243 : // Encode load balance attribute.
244 528967 : if (!load_balance_attribute_.IsDefault())
245 4 : load_balance_attribute_.Encode(&item.entry.load_balance);
246 :
247 528970 : xml_node node = doc_.append_child("item");
248 528900 : node.append_attribute("id") = route->ToXmppIdString().c_str();
249 :
250 : // Remember the previous size.
251 : // Using remove_child instead of reset allows memory pages allocated for
252 : // the xml_document to be reused during the lifetime of the xml_document.
253 529008 : size_t pos = repr_.size();
254 528996 : item.Encode(&node);
255 528964 : doc_.print(writer_, "\t", pugi::format_default, pugi::encoding_auto, 3);
256 529134 : doc_.remove_child(node);
257 :
258 : // Cache the substring starting at the previous size.
259 529108 : if (cache_routes_)
260 28011 : roattr->set_repr(repr_, pos);
261 529109 : }
262 :
263 250023 : void BgpXmppMessage::AddIpUnreach(const BgpRoute *route) {
264 250023 : repr_ += "\t\t\t<retract id=\"" + route->ToXmppIdString() + "\" />\n";
265 250121 : }
266 :
267 556643 : bool BgpXmppMessage::AddInetRoute(const BgpRoute *route,
268 : const RibOutAttr *roattr) {
269 556643 : if (is_reachable_) {
270 424850 : num_reach_route_++;
271 424850 : AddIpReach(route, roattr);
272 : } else {
273 131793 : num_unreach_route_++;
274 131793 : AddIpUnreach(route);
275 : }
276 556705 : return true;
277 : }
278 :
279 320730 : bool BgpXmppMessage::AddInet6Route(const BgpRoute *route,
280 : const RibOutAttr *roattr) {
281 320730 : if (is_reachable_) {
282 202479 : num_reach_route_++;
283 202479 : AddIpReach(route, roattr);
284 : } else {
285 118251 : num_unreach_route_++;
286 118251 : AddIpUnreach(route);
287 : }
288 320740 : return true;
289 : }
290 :
291 9071 : void BgpXmppMessage::EncodeEnetNextHop(const BgpRoute *route,
292 : const RibOutAttr::NextHop &nexthop,
293 : autogen::EnetItemType *item) {
294 9071 : autogen::EnetNextHopType item_nexthop;
295 :
296 9071 : item_nexthop.af = BgpAf::IPv4;
297 9071 : item_nexthop.address = nexthop.address().to_v4().to_string();
298 9070 : item_nexthop.label = nexthop.label();
299 9071 : item_nexthop.l3_label = nexthop.l3_label();
300 9071 : if (!nexthop.mac().IsZero())
301 20 : item_nexthop.mac = nexthop.mac().ToString();
302 :
303 : // If encap list is empty use mpls over gre as default encap.
304 9071 : vector<string> &encap_list =
305 : item_nexthop.tunnel_encapsulation_list.tunnel_encapsulation;
306 9071 : if (nexthop.encap().empty()) {
307 0 : encap_list.push_back(string("gre"));
308 : } else {
309 9071 : encap_list = nexthop.encap();
310 : }
311 9071 : item_nexthop.tag_list.tag = nexthop.tag_list();
312 9070 : item_nexthop.is_new_tags_list = true;
313 9070 : item->entry.next_hops.next_hop.push_back(item_nexthop);
314 9071 : }
315 :
316 10519 : void BgpXmppMessage::AddEnetReach(const BgpRoute *route,
317 : const RibOutAttr *roattr) {
318 10519 : if (!roattr->repr().empty()) {
319 0 : repr_ += roattr->repr();
320 0 : return;
321 : }
322 10519 : Address::Family family = table_->family();
323 :
324 10519 : autogen::EnetItemType item;
325 10519 : item.entry.nlri.af = BgpAf::FamilyToAfi(family);
326 10519 : item.entry.nlri.safi = BgpAf::FamilyToXmppSafi(family);
327 :
328 10519 : EvpnRoute *evpn_route =
329 : static_cast<EvpnRoute *>(const_cast<BgpRoute *>(route));
330 10519 : const EvpnPrefix &evpn_prefix = evpn_route->GetPrefix();
331 10519 : item.entry.nlri.ethernet_tag = evpn_prefix.tag();
332 10519 : item.entry.nlri.mac = evpn_prefix.mac_addr().ToString();
333 21038 : item.entry.nlri.address = evpn_prefix.ip_address().to_string() + "/" +
334 31557 : integerToString(evpn_prefix.ip_address_length());
335 10519 : item.entry.nlri.source = evpn_prefix.source().to_string();
336 10519 : item.entry.nlri.group = evpn_prefix.group().to_string();
337 :
338 10519 : item.entry.virtual_network = GetVirtualNetwork(route, roattr);
339 10519 : item.entry.local_preference = roattr->attr()->local_pref();
340 10519 : item.entry.med = roattr->attr()->med();
341 10519 : item.entry.sequence_number = mobility_.sequence_number;
342 10519 : item.entry.mobility.seqno = mobility_.sequence_number;
343 10519 : item.entry.mobility.sticky = mobility_.sticky;
344 10519 : item.entry.etree_leaf = etree_leaf_;
345 :
346 10519 : for (vector<int>::const_iterator it = security_group_list_.begin();
347 21046 : it != security_group_list_.end(); ++it) {
348 10527 : item.entry.security_group_list.security_group.push_back(*it);
349 : }
350 :
351 10519 : const BgpOList *olist = roattr->attr()->olist().get();
352 10519 : assert((olist == NULL) != roattr->nexthop_list().empty());
353 :
354 10519 : if (olist) {
355 1576 : assert(olist->olist().subcode == BgpAttribute::OList);
356 14778 : BOOST_FOREACH(const BgpOListElem *elem, olist->elements()) {
357 6601 : autogen::EnetNextHopType nh;
358 6601 : nh.af = BgpAf::IPv4;
359 6601 : nh.address = elem->address.to_string();
360 6601 : nh.label = elem->label;
361 6601 : nh.tunnel_encapsulation_list.tunnel_encapsulation = elem->encap;
362 6601 : item.entry.olist.next_hop.push_back(nh);
363 6601 : }
364 : }
365 :
366 10519 : const BgpOList *leaf_olist = roattr->attr()->leaf_olist().get();
367 10519 : assert((leaf_olist == NULL) != roattr->nexthop_list().empty());
368 :
369 10519 : if (leaf_olist) {
370 1576 : assert(leaf_olist->olist().subcode == BgpAttribute::LeafOList);
371 1576 : BOOST_FOREACH(const BgpOListElem *elem, leaf_olist->elements()) {
372 0 : autogen::EnetNextHopType nh;
373 0 : nh.af = BgpAf::IPv4;
374 0 : nh.address = elem->address.to_string();
375 0 : nh.label = elem->label;
376 0 : nh.tunnel_encapsulation_list.tunnel_encapsulation = elem->encap;
377 0 : item.entry.leaf_olist.next_hop.push_back(nh);
378 0 : }
379 : }
380 :
381 28661 : BOOST_FOREACH(const RibOutAttr::NextHop &nexthop, roattr->nexthop_list()) {
382 9071 : EncodeEnetNextHop(route, nexthop, &item);
383 : }
384 :
385 11429 : for (const auto &peer_name : route->peer_sources()) {
386 910 : item.entry.peers.peer.push_back(peer_name);
387 : }
388 :
389 10519 : xml_node node = doc_.append_child("item");
390 10519 : node.append_attribute("id") = route->ToXmppIdString().c_str();
391 :
392 : // Remember the previous size.
393 : // Using remove_child instead of reset allows memory pages allocated for
394 : // the xml_document to be reused during the lifetime of the xml_document.
395 10519 : size_t pos = repr_.size();
396 10519 : item.Encode(&node);
397 10519 : doc_.print(writer_, "\t", pugi::format_default, pugi::encoding_auto, 3);
398 10519 : doc_.remove_child(node);
399 :
400 : // Cache the substring starting at the previous size.
401 10519 : if (cache_routes_)
402 2009 : roattr->set_repr(repr_, pos);
403 10519 : }
404 :
405 1992 : void BgpXmppMessage::AddEnetUnreach(const BgpRoute *route) {
406 1992 : repr_ += "\t\t\t<retract id=\"" + route->ToXmppIdString() + "\" />\n";
407 1992 : }
408 :
409 12511 : bool BgpXmppMessage::AddEnetRoute(const BgpRoute *route,
410 : const RibOutAttr *roattr) {
411 12511 : if (is_reachable_) {
412 10519 : num_reach_route_++;
413 10519 : AddEnetReach(route, roattr);
414 : } else {
415 1992 : num_unreach_route_++;
416 1992 : AddEnetUnreach(route);
417 : }
418 12511 : return true;
419 : }
420 :
421 : //
422 : // Note that there's no need to cache the string representation since a given
423 : // mcast route is sent to exactly one xmpp peer.
424 : //
425 2329 : void BgpXmppMessage::AddMcastReach(const BgpRoute *route,
426 : const RibOutAttr *roattr) {
427 2329 : Address::Family family = table_->family();
428 2329 : autogen::McastItemType item;
429 2329 : item.entry.nlri.af = BgpAf::FamilyToAfi(family);
430 2329 : item.entry.nlri.safi = BgpAf::FamilyToXmppSafi(family);
431 :
432 2329 : ErmVpnRoute *ermvpn_route =
433 : static_cast<ErmVpnRoute *>(const_cast<BgpRoute *>(route));
434 2329 : item.entry.nlri.group = ermvpn_route->GetPrefix().group().to_string();
435 2329 : item.entry.nlri.source = ermvpn_route->GetPrefix().source().to_string();
436 2329 : item.entry.nlri.source_label = roattr->label();
437 2329 : if (!roattr->source_address().is_unspecified()) {
438 : item.entry.nlri.source_address =
439 147 : roattr->source_address().to_string();
440 : }
441 :
442 2329 : const BgpOList *olist = roattr->attr()->olist().get();
443 2329 : assert(olist->olist().subcode == BgpAttribute::OList);
444 7349 : BOOST_FOREACH(const BgpOListElem *elem, olist->elements()) {
445 2510 : autogen::McastNextHopType nh;
446 2510 : nh.af = BgpAf::IPv4;
447 2510 : nh.address = elem->address.to_string();
448 2510 : nh.label = integerToString(elem->label);
449 2510 : nh.tunnel_encapsulation_list.tunnel_encapsulation = elem->encap;
450 2510 : item.entry.olist.next_hop.push_back(nh);
451 2510 : }
452 :
453 : // Using remove_child instead of reset allows memory pages allocated for
454 : // the xml_document to be reused during the lifetime of the xml_document.
455 2329 : xml_node node = doc_.append_child("item");
456 2329 : node.append_attribute("id") = route->ToXmppIdString().c_str();
457 2329 : item.Encode(&node);
458 2329 : doc_.print(writer_, "\t", pugi::format_default, pugi::encoding_auto, 3);
459 2329 : doc_.remove_child(node);
460 2329 : }
461 :
462 474 : void BgpXmppMessage::AddMcastUnreach(const BgpRoute *route) {
463 474 : repr_ += "\t\t\t<retract id=\"" + route->ToXmppIdString() + "\" />\n";
464 474 : }
465 :
466 2803 : bool BgpXmppMessage::AddMcastRoute(const BgpRoute *route,
467 : const RibOutAttr *roattr) {
468 2803 : if (is_reachable_) {
469 2329 : num_reach_route_++;
470 2329 : AddMcastReach(route, roattr);
471 : } else {
472 474 : num_unreach_route_++;
473 474 : AddMcastUnreach(route);
474 : }
475 2803 : return true;
476 : }
477 :
478 196816 : void BgpXmppMessage::AddMvpnReach(const BgpRoute *route,
479 : const RibOutAttr *roattr) {
480 196816 : Address::Family family = table_->family();
481 196816 : autogen::MvpnItemType item;
482 196816 : item.entry.nlri.af = BgpAf::FamilyToAfi(family);
483 196816 : item.entry.nlri.safi = BgpAf::FamilyToXmppSafi(family);
484 :
485 196816 : MvpnRoute *mvpn_route =
486 : static_cast<MvpnRoute *>(const_cast<BgpRoute *>(route));
487 196816 : item.entry.nlri.group = mvpn_route->GetPrefix().group().to_string();
488 196816 : item.entry.nlri.source = mvpn_route->GetPrefix().source().to_string();
489 196816 : item.entry.nlri.route_type = mvpn_route->GetPrefix().type();
490 196816 : assert((item.entry.nlri.route_type == MvpnPrefix::SourceActiveADRoute) ||
491 : (item.entry.nlri.route_type == MvpnPrefix::SourceTreeJoinRoute));
492 :
493 196816 : if (item.entry.nlri.route_type == MvpnPrefix::SourceActiveADRoute) {
494 196722 : const BgpOList *olist = roattr->attr()->olist().get();
495 196722 : assert(olist->olist().subcode == BgpAttribute::OList);
496 590166 : BOOST_FOREACH(const BgpOListElem *elem, olist->elements()) {
497 196722 : autogen::MvpnNextHopType nh;
498 196722 : nh.af = BgpAf::IPv4;
499 196722 : nh.address = elem->address.to_string();
500 196722 : nh.label = elem->label;
501 196722 : nh.tunnel_encapsulation_list.tunnel_encapsulation = elem->encap;
502 196722 : item.entry.olist.next_hop.push_back(nh);
503 196722 : }
504 : }
505 :
506 : // Using remove_child instead of reset allows memory pages allocated for
507 : // the xml_document to be reused during the lifetime of the xml_document.
508 196816 : xml_node node = doc_.append_child("item");
509 196816 : node.append_attribute("id") = route->ToXmppIdString().c_str();
510 196816 : item.Encode(&node);
511 196816 : doc_.print(writer_, "\t", pugi::format_default, pugi::encoding_auto, 3);
512 196816 : doc_.remove_child(node);
513 196816 : }
514 :
515 123 : void BgpXmppMessage::AddMvpnUnreach(const BgpRoute *route) {
516 123 : repr_ += "\t\t\t<retract id=\"" + route->ToXmppIdString() + "\" />\n";
517 123 : }
518 :
519 196939 : bool BgpXmppMessage::AddMvpnRoute(const BgpRoute *route,
520 : const RibOutAttr *roattr) {
521 196939 : if (is_reachable_) {
522 196816 : num_reach_route_++;
523 196816 : AddMvpnReach(route, roattr);
524 : } else {
525 123 : num_unreach_route_++;
526 123 : AddMvpnUnreach(route);
527 : }
528 196939 : return true;
529 : }
530 :
531 14152859 : const uint8_t *BgpXmppMessage::GetData(IPeerUpdate *peer, size_t *lenp,
532 : const string **msg_str, string *temp) {
533 : // Build begin line that contains message opening tag with from and to
534 : // attributes.
535 14152859 : msg_begin_.clear();
536 14152922 : msg_begin_ += "\n<message from=\"";
537 14153013 : msg_begin_ += XmppInit::kControlNodeJID;
538 14153118 : msg_begin_ += "\" to=\"";
539 14153204 : msg_begin_ += peer->ToString();
540 14153318 : msg_begin_ += "/";
541 14153330 : msg_begin_ += XmppInit::kBgpPeer;
542 14153286 : msg_begin_ += "\">";
543 :
544 : // Add closing tags if this is the first peer to which the message will
545 : // be sent.
546 14153300 : if (!repr_valid_) {
547 468584 : repr_ += "\t\t</items>\n\t</event>\n</message>\n";
548 468582 : repr_valid_ = true;
549 : }
550 :
551 : // Replace the begin line if it fits in the space reserved at the start
552 : // of repr_. Use fill and copy instead of string::replace as the latter
553 : // seems to construct a new temporary string to hold the input data to
554 : // be copied.
555 : // Otherwise build a new string with the begin line and the rest of the
556 : // message in repr_.
557 14153298 : size_t begin_size = msg_begin_.size();
558 14153251 : if (begin_size <= kMaxFromToLength) {
559 9958963 : size_t extra = kMaxFromToLength - begin_size;
560 9958963 : char *data = const_cast<char *>(repr_.c_str());
561 9958973 : fill(data, data + extra, ' ');
562 9958936 : copy(msg_begin_.c_str(), msg_begin_.c_str() + begin_size, data + extra);
563 9958769 : *lenp = repr_.size() - extra;
564 9958764 : *msg_str = &repr_;
565 9958764 : return reinterpret_cast<const uint8_t *>(repr_.c_str()) + extra;
566 : } else {
567 4194288 : *temp = msg_begin_ + string(repr_, kMaxFromToLength);
568 4194304 : *lenp = temp->size();
569 4194304 : *msg_str = NULL;
570 4194304 : return reinterpret_cast<const uint8_t *>(temp->c_str());
571 : }
572 : }
573 :
574 836877 : void BgpXmppMessage::ProcessCommunity(const Community *community) {
575 836877 : community_list_.clear();
576 836882 : if (community == NULL)
577 825076 : return;
578 35451 : BOOST_FOREACH(uint32_t value, community->communities()) {
579 11827 : community_list_.push_back(CommunityType::CommunityToString(value));
580 : }
581 : }
582 :
583 836856 : void BgpXmppMessage::ProcessExtCommunity(const ExtCommunity *ext_community) {
584 836856 : mobility_.sequence_number = 0;
585 836856 : mobility_.sticky = false;
586 836856 : etree_leaf_ = false;
587 836856 : security_group_list_.clear();
588 836863 : load_balance_attribute_ = LoadBalance::LoadBalanceAttribute();
589 837077 : if (ext_community == NULL)
590 207993 : return;
591 :
592 629084 : as_t as_number = table_->server()->autonomous_system();
593 629039 : bool sg_asn_match = true;
594 629008 : for (ExtCommunity::ExtCommunityList::const_iterator iter =
595 629039 : ext_community->communities().begin();
596 3684950 : iter != ext_community->communities().end(); ++iter) {
597 3055991 : if (ExtCommunity::is_security_group(*iter)) {
598 431857 : SecurityGroup sg(*iter);
599 431849 : if (as_number <= AS2_MAX)
600 235242 : if (sg.as_number() != as_number && !sg.IsGlobal())
601 2 : continue;
602 431867 : security_group_list_.push_back(sg.security_group_id());
603 2624227 : } else if (ExtCommunity::is_security_group4(*iter)) {
604 196608 : SecurityGroup4ByteAs sg(*iter);
605 196608 : if (sg.as_number() != as_number)
606 0 : sg_asn_match = false;
607 2427559 : } else if (ExtCommunity::is_mac_mobility(*iter)) {
608 1079 : MacMobility mm(*iter);
609 1079 : mobility_.sequence_number = mm.sequence_number();
610 1079 : mobility_.sticky = mm.sticky();
611 2426469 : } else if (ExtCommunity::is_load_balance(*iter)) {
612 4 : LoadBalance load_balance(*iter);
613 4 : load_balance.FillAttribute(&load_balance_attribute_);
614 2426452 : } else if (ExtCommunity::is_etree(*iter)) {
615 9385 : ETree etree(*iter);
616 9385 : etree_leaf_ = etree.leaf();
617 : }
618 : }
619 628915 : if (!sg_asn_match)
620 0 : security_group_list_.clear();
621 : }
622 :
623 1069456 : string BgpXmppMessage::GetVirtualNetwork(
624 : const RibOutAttr::NextHop &nexthop) const {
625 1069456 : int index = nexthop.origin_vn_index();
626 1069460 : if (index > 0) {
627 : const RoutingInstanceMgr *manager =
628 68942 : table_->routing_instance()->manager();
629 68946 : return manager->GetVirtualNetworkByVnIndex(index);
630 1000518 : } else if (index == 0) {
631 61341 : return table_->routing_instance()->GetVirtualNetworkName();
632 : } else {
633 939177 : return "unresolved";
634 : }
635 : }
636 :
637 539639 : string BgpXmppMessage::GetVirtualNetwork(const BgpRoute *route,
638 : const RibOutAttr *roattr) const {
639 539639 : if (!is_reachable_) {
640 0 : return "unresolved";
641 539639 : } else if (roattr->nexthop_list().empty()) {
642 1576 : if (roattr->vrf_originated()) {
643 1576 : return table_->routing_instance()->GetVirtualNetworkName();
644 : } else {
645 0 : return "unresolved";
646 : }
647 : } else {
648 538000 : return GetVirtualNetwork(roattr->nexthop_list().front());
649 : }
650 : }
651 :
652 50 : BgpXmppMessageBuilder::BgpXmppMessageBuilder() {
653 50 : }
654 :
655 144 : Message *BgpXmppMessageBuilder::Create() const {
656 144 : return new BgpXmppMessage;
657 : }
|