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_config_parser.h"
7 :
8 : #include <boost/uuid/name_generator.hpp>
9 : #include <pugixml/pugixml.hpp>
10 :
11 : #include <map>
12 : #include <set>
13 : #include <sstream>
14 : #include <utility>
15 : #include <vector>
16 :
17 : #include "bgp/bgp_config.h"
18 : #include "bgp/bgp_log.h"
19 : #include "bgp/rtarget/rtarget_address.h"
20 : #include "ifmap/ifmap_server_table.h"
21 :
22 : #include "schema/bgp_schema_types.h"
23 : #include "schema/vnc_cfg_types.h"
24 :
25 : using pugi::xml_attribute;
26 : using pugi::xml_document;
27 : using pugi::xml_node;
28 : using pugi::xml_parse_result;
29 : using std::unique_ptr;
30 : using std::istringstream;
31 : using std::list;
32 : using std::ostringstream;
33 : using std::make_pair;
34 : using std::map;
35 : using std::multimap;
36 : using std::pair;
37 : using std::set;
38 : using std::string;
39 : using std::vector;
40 :
41 : typedef multimap<
42 : pair<string, string>,
43 : pair<autogen::BgpSessionAttributes, string> > SessionMap;
44 :
45 : namespace {
46 :
47 24470 : static void MapObjectSetProperty(const string <ype, const string &lname,
48 : const string &propname,
49 : AutogenProperty *property,
50 : BgpConfigParser::RequestList *requests) {
51 24470 : DBRequest *request = new DBRequest;
52 24470 : request->oper = DBRequest::DB_ENTRY_ADD_CHANGE;
53 24470 : IFMapTable::RequestKey *key = new IFMapTable::RequestKey();
54 24470 : request->key.reset(key);
55 24470 : key->id_type = ltype;
56 24470 : key->id_name = lname;
57 24470 : IFMapServerTable::RequestData *data = new IFMapServerTable::RequestData();
58 24470 : request->data.reset(data);
59 24470 : data->metadata = propname;
60 24470 : data->content.reset(property);
61 24470 : data->origin.set_origin(IFMapOrigin::MAP_SERVER);
62 24470 : requests->push_back(request);
63 24470 : }
64 :
65 5603 : static void MapObjectClearProperty(const string <ype, const string &lname,
66 : const string &propname,
67 : BgpConfigParser::RequestList *requests) {
68 5603 : DBRequest *request = new DBRequest;
69 5603 : request->oper = DBRequest::DB_ENTRY_DELETE;
70 5603 : IFMapTable::RequestKey *key = new IFMapTable::RequestKey();
71 5603 : request->key.reset(key);
72 5603 : key->id_type = ltype;
73 5603 : key->id_name = lname;
74 5603 : IFMapServerTable::RequestData *data = new IFMapServerTable::RequestData();
75 5603 : request->data.reset(data);
76 5603 : data->metadata = propname;
77 5603 : data->origin.set_origin(IFMapOrigin::MAP_SERVER);
78 5603 : requests->push_back(request);
79 5603 : }
80 :
81 19272 : static void MapObjectLink(const string <ype, const string &lname,
82 : const string &rtype, const string &rname,
83 : const string &linkname,
84 : BgpConfigParser::RequestList *requests) {
85 19272 : DBRequest *request = new DBRequest;
86 19272 : request->oper = DBRequest::DB_ENTRY_ADD_CHANGE;
87 19272 : IFMapTable::RequestKey *key = new IFMapTable::RequestKey();
88 19272 : request->key.reset(key);
89 19272 : key->id_type = ltype;
90 19272 : key->id_name = lname;
91 19272 : IFMapServerTable::RequestData *data = new IFMapServerTable::RequestData();
92 19272 : request->data.reset(data);
93 19272 : data->metadata = linkname;
94 19272 : data->id_type = rtype;
95 19272 : data->id_name = rname;
96 19272 : data->origin.set_origin(IFMapOrigin::MAP_SERVER);
97 19272 : requests->push_back(request);
98 19272 : }
99 :
100 17922 : static void MapObjectUnlink(const string <ype, const string &lname,
101 : const string &rtype, const string &rname,
102 : const string &linkname,
103 : BgpConfigParser::RequestList *requests) {
104 17922 : DBRequest *request = new DBRequest;
105 17922 : request->oper = DBRequest::DB_ENTRY_DELETE;
106 17922 : IFMapTable::RequestKey *key = new IFMapTable::RequestKey();
107 17922 : request->key.reset(key);
108 17922 : key->id_type = ltype;
109 17922 : key->id_name = lname;
110 17922 : IFMapServerTable::RequestData *data = new IFMapServerTable::RequestData();
111 17922 : request->data.reset(data);
112 17922 : data->metadata = linkname;
113 17922 : data->id_type = rtype;
114 17922 : data->id_name = rname;
115 17922 : data->origin.set_origin(IFMapOrigin::MAP_SERVER);
116 17922 : requests->push_back(request);
117 17922 : }
118 :
119 43193 : static void MapObjectLinkAttr(const string <ype, const string &lname,
120 : const string &rtype, const string &rname,
121 : const string &linkname, AutogenProperty *attr,
122 : BgpConfigParser::RequestList *requests) {
123 43193 : DBRequest *request = new DBRequest;
124 43193 : request->oper = DBRequest::DB_ENTRY_ADD_CHANGE;
125 43193 : IFMapTable::RequestKey *key = new IFMapTable::RequestKey();
126 43193 : request->key.reset(key);
127 43193 : key->id_type = ltype;
128 43193 : key->id_name = lname;
129 43193 : IFMapServerTable::RequestData *data = new IFMapServerTable::RequestData();
130 43193 : request->data.reset(data);
131 43193 : data->metadata = linkname;
132 43193 : data->id_type = rtype;
133 43193 : data->id_name = rname;
134 43193 : data->content.reset(attr);
135 43193 : data->origin.set_origin(IFMapOrigin::MAP_SERVER);
136 43193 : requests->push_back(request);
137 43193 : }
138 :
139 25567 : static autogen::BgpSessionAttributes *GetPeeringSessionAttribute(
140 : const pair<string, string> &key, autogen::BgpPeeringAttributes *peer,
141 : int session_id, const string config_uuid) {
142 25567 : string uuid;
143 25567 : if (!config_uuid.empty()) {
144 14480 : uuid = config_uuid;
145 : } else {
146 11087 : uuid = BgpConfigParser::session_uuid(key.first, key.second, session_id);
147 : }
148 :
149 25567 : autogen::BgpSession *session = NULL;
150 25567 : for (vector<autogen::BgpSession>::iterator iter =
151 25567 : peer->session.begin();
152 60209 : iter != peer->session.end(); ++iter) {
153 46233 : if (iter->uuid == uuid) {
154 11591 : session = iter.operator->();
155 11591 : break;
156 : }
157 : }
158 25567 : if (session == NULL) {
159 13976 : peer->session.push_back(autogen::BgpSession());
160 13976 : session = &peer->session.back();
161 13976 : session->uuid = uuid;
162 : }
163 25567 : session->attributes.push_back(autogen::BgpSessionAttributes());
164 25567 : autogen::BgpSessionAttributes *sattr = &session->attributes.back();
165 25567 : return sattr;
166 25567 : }
167 :
168 7498 : static void MaybeMergeBidirectionalSessionParams(
169 : autogen::BgpPeeringAttributes *peer) {
170 7498 : }
171 :
172 38742 : static void BuildPeeringLinks(const string &instance,
173 : const SessionMap &sessions,
174 : BgpConfigParser::RequestList *requests) {
175 : typedef map<pair<string, string>, autogen::BgpPeeringAttributes *>
176 : PeeringMap;
177 38742 : PeeringMap peerings;
178 :
179 38742 : pair<string, string> sprev;
180 38742 : int session_id = 0;
181 38742 : for (SessionMap::const_iterator iter = sessions.begin();
182 64309 : iter != sessions.end(); ++iter) {
183 25567 : const string &left = iter->first.first;
184 25567 : const string &right = iter->first.second;
185 25567 : pair<string, string> key;
186 25567 : if (left <= right) {
187 13976 : key = make_pair(left, right);
188 : } else {
189 11591 : key = make_pair(right, left);
190 : }
191 :
192 25567 : string config_uuid = iter->second.second;
193 25567 : if ((sprev.first == left) && (sprev.second == right)) {
194 12956 : session_id++;
195 : } else {
196 12611 : session_id = 1;
197 12611 : sprev = make_pair(left, right);
198 : }
199 :
200 25567 : autogen::BgpPeeringAttributes *peer = NULL;
201 25567 : PeeringMap::iterator loc = peerings.find(key);
202 25567 : if (loc == peerings.end()) {
203 7498 : peer = new autogen::BgpPeeringAttributes();
204 7498 : peerings.insert(make_pair(key, peer));
205 : } else {
206 18069 : peer = loc->second;
207 : }
208 : // add uni-directional attributes for this session.
209 : autogen::BgpSessionAttributes *attrp =
210 25567 : GetPeeringSessionAttribute(key, peer, session_id, config_uuid);
211 25567 : attrp->Copy(iter->second.first);
212 25567 : attrp->bgp_router = left;
213 25567 : }
214 :
215 : // generate the links.
216 : // merging uni-directional attributes into a common attribute when they
217 : // are the same.
218 46240 : for (PeeringMap::iterator iter = peerings.begin(); iter != peerings.end();
219 7498 : ++iter) {
220 7498 : autogen::BgpPeeringAttributes *peer = iter->second;
221 7498 : MaybeMergeBidirectionalSessionParams(peer);
222 7498 : string left(instance + ':'), right(instance + ':');
223 7498 : left.append(iter->first.first);
224 7498 : right.append(iter->first.second);
225 7498 : MapObjectLinkAttr("bgp-router", left, "bgp-router", right,
226 : "bgp-peering", peer, requests);
227 7498 : }
228 38742 : }
229 :
230 14600 : static void RemovePeeringLinks(const string &instance,
231 : const SessionMap &sessions,
232 : BgpConfigParser::RequestList *requests) {
233 14600 : set<pair<string, string> > key_set;
234 :
235 14600 : for (SessionMap::const_iterator iter = sessions.begin();
236 18820 : iter != sessions.end(); ++iter) {
237 4220 : const string &left = iter->first.first;
238 4220 : const string &right = iter->first.second;
239 4220 : pair<string, string> key;
240 4220 : if (left <= right) {
241 2112 : key = make_pair(left, right);
242 : } else {
243 2108 : key = make_pair(right, left);
244 : }
245 4220 : if (key_set.count(key) > 0) {
246 3647 : continue;
247 : }
248 573 : key_set.insert(key);
249 573 : string id_left(instance + ':'), id_right(instance + ':');
250 573 : id_left.append(key.first);
251 573 : id_right.append(key.second);
252 :
253 573 : MapObjectUnlink("bgp-router", id_left, "bgp-router", id_right,
254 : "bgp-peering", requests);
255 4220 : }
256 14600 : }
257 :
258 29787 : static bool ParseSession(const string &identifier, const xml_node &node,
259 : SessionMap *sessions) {
260 29787 : autogen::BgpSessionAttributes attr;
261 29787 : attr.Clear();
262 29787 : xml_attribute to = node.attribute("to");
263 29787 : assert(to);
264 29787 : assert(attr.XmlParse(node));
265 :
266 29787 : string to_value = to.value();
267 29787 : string to_name, uuid;
268 29787 : size_t pos = to_value.find(':');
269 29787 : if (pos == string::npos) {
270 11106 : to_name = to_value;
271 : } else {
272 18681 : to_name = to_value.substr(0, pos);
273 18681 : uuid = string(to_value, pos + 1);
274 : }
275 :
276 29787 : sessions->insert(
277 59574 : make_pair(make_pair(identifier, to_name), make_pair(attr, uuid)));
278 29787 : return true;
279 29787 : }
280 :
281 443 : static bool ParseServiceChain(const string &instance, const xml_node &node,
282 : bool add_change, const string &sc_info,
283 : BgpConfigParser::RequestList *requests) {
284 : unique_ptr<autogen::ServiceChainInfo> property(
285 443 : new autogen::ServiceChainInfo());
286 443 : property->sc_head = true;
287 443 : assert(property->XmlParse(node));
288 :
289 443 : if (add_change) {
290 409 : MapObjectSetProperty("routing-instance", instance,
291 409 : sc_info, property.release(), requests);
292 : } else {
293 34 : MapObjectClearProperty("routing-instance", instance,
294 : sc_info, requests);
295 : }
296 :
297 443 : return true;
298 443 : }
299 :
300 346 : static bool ParseInstanceRouteAggregate(const string &instance,
301 : const xml_node &node, bool add_change,
302 : BgpConfigParser::RequestList *requests) {
303 :
304 346 : xml_attribute to = node.attribute("to");
305 346 : assert(to);
306 346 : string aggregate_name = to.value();
307 346 : if (add_change) {
308 222 : MapObjectLinkAttr("routing-instance", instance,
309 : "route-aggregate", aggregate_name,
310 : "route-aggregate-routing-instance", NULL, requests);
311 : } else {
312 124 : MapObjectUnlink("routing-instance", instance,
313 : "route-aggregate", aggregate_name,
314 : "route-aggregate-routing-instance", requests);
315 : }
316 :
317 346 : return true;
318 346 : }
319 :
320 235 : static bool ParseInstanceRoutingPolicy(const string &instance,
321 : const xml_node &node, bool add_change,
322 : BgpConfigParser::RequestList *requests) {
323 :
324 235 : xml_attribute to = node.attribute("to");
325 235 : assert(to);
326 235 : string policy_name = to.value();
327 : unique_ptr<autogen::RoutingPolicyType> attr(
328 235 : new autogen::RoutingPolicyType());
329 235 : assert(attr->XmlParse(node));
330 235 : if (add_change) {
331 187 : MapObjectLinkAttr("routing-instance", instance,
332 : "routing-policy", policy_name,
333 187 : "routing-policy-routing-instance", attr.release(), requests);
334 : } else {
335 48 : MapObjectUnlink("routing-instance", instance,
336 : "routing-policy", policy_name,
337 : "routing-policy-routing-instance", requests);
338 : }
339 :
340 235 : return true;
341 235 : }
342 :
343 67 : static bool ParseStaticRoute(const string &instance, const xml_node &node,
344 : bool add_change,
345 : BgpConfigParser::RequestList *requests) {
346 : unique_ptr<autogen::StaticRouteEntriesType> property(
347 67 : new autogen::StaticRouteEntriesType());
348 67 : assert(property->XmlParse(node));
349 :
350 67 : if (add_change) {
351 34 : MapObjectSetProperty("routing-instance", instance,
352 34 : "static-route-entries", property.release(), requests);
353 : } else {
354 33 : MapObjectClearProperty("routing-instance", instance,
355 : "static-route-entries", requests);
356 : }
357 :
358 67 : return true;
359 67 : }
360 :
361 96 : static bool ParseInstanceHasPnf(const string &instance, const xml_node &node,
362 : bool add_change, BgpConfigParser::RequestList *requests) {
363 : unique_ptr<autogen::RoutingInstance::OolProperty> property(
364 96 : new autogen::RoutingInstance::OolProperty);
365 96 : property->data = (string(node.child_value()) == "true");
366 96 : if (add_change) {
367 64 : MapObjectSetProperty("routing-instance", instance,
368 64 : "routing-instance-has-pnf", property.release(), requests);
369 : } else {
370 32 : MapObjectClearProperty("routing-instance", instance,
371 : "routing-instance-has-pnf", requests);
372 : }
373 :
374 96 : return true;
375 96 : }
376 :
377 17902 : static bool ParseBgpRouter(const string &instance, const xml_node &node,
378 : bool add_change, string *nodename,
379 : SessionMap *sessions,
380 : BgpConfigParser::RequestList *requests) {
381 : unique_ptr<autogen::BgpRouterParams> property(
382 17902 : new autogen::BgpRouterParams());
383 17902 : xml_attribute name = node.attribute("name");
384 17902 : assert(name);
385 17902 : string identifier = name.value();
386 17902 : assert(property->XmlParse(node));
387 :
388 17902 : if (property->autonomous_system == 0) {
389 5113 : property->autonomous_system =
390 5113 : BgpConfigManager::kDefaultAutonomousSystem;
391 : }
392 17902 : if (property->identifier.empty()) {
393 8168 : property->identifier = property->address;
394 : }
395 :
396 17902 : bool has_sessions = false;
397 47689 : for (xml_node xsession = node.child("session"); xsession;
398 29787 : xsession = xsession.next_sibling("session")) {
399 29787 : has_sessions = true;
400 29787 : ParseSession(identifier, xsession, sessions);
401 : }
402 :
403 17902 : string fqname(instance + ":" + identifier);
404 17902 : if (!has_sessions) {
405 6692 : *nodename = fqname;
406 : }
407 :
408 17902 : string subcluster_name;
409 17902 : if (node.child("sub-cluster")) {
410 16 : xml_attribute sc = node.child("sub-cluster").attribute("name");
411 16 : subcluster_name = sc.value();
412 16 : assert(!subcluster_name.empty());
413 : }
414 :
415 17902 : if (add_change) {
416 14480 : MapObjectLink("routing-instance", instance,
417 : "bgp-router", fqname, "instance-bgp-router", requests);
418 14480 : MapObjectSetProperty("bgp-router", fqname,
419 14480 : "bgp-router-parameters", property.release(), requests);
420 14480 : if (!subcluster_name.empty()) {
421 16 : MapObjectLink("bgp-router", fqname, "sub-cluster", subcluster_name,
422 : "bgp-router-sub-cluster", requests);
423 : }
424 : } else {
425 3422 : MapObjectClearProperty("bgp-router", fqname,
426 : "bgp-router-parameters", requests);
427 3422 : MapObjectUnlink("routing-instance", instance,
428 : "bgp-router", fqname, "instance-bgp-router", requests);
429 3422 : if (!subcluster_name.empty()) {
430 0 : MapObjectUnlink("bgp-router", fqname, "sub-cluster",
431 : subcluster_name, "bgp-router-sub-cluster", requests);
432 : }
433 : }
434 :
435 17902 : return true;
436 17902 : }
437 :
438 : // Creates a full-mesh of links between all the routers that have been
439 : // defined.
440 38742 : static void AddNeighborMesh(const list<string> &routers,
441 : BgpConfigParser::RequestList *requests) {
442 38742 : for (list<string>::const_iterator iter = routers.begin();
443 43124 : iter != routers.end(); ) {
444 4382 : const string &left = *iter;
445 4382 : ++iter;
446 4382 : for (list<string>::const_iterator tgt = iter;
447 4634 : tgt != routers.end(); ++tgt) {
448 252 : MapObjectLink("bgp-router", left, "bgp-router", *tgt, "bgp-peering",
449 : requests);
450 : }
451 : }
452 38742 : }
453 :
454 14600 : static void DeleteNeighborMesh(const list<string> &routers,
455 : BgpConfigParser::RequestList *requests) {
456 14600 : for (list<string>::const_iterator iter = routers.begin();
457 16910 : iter != routers.end(); ) {
458 2310 : const string &left = *iter;
459 2310 : ++iter;
460 2310 : for (list<string>::const_iterator tgt = iter;
461 4571 : tgt != routers.end(); ++tgt) {
462 2261 : MapObjectUnlink("bgp-router", left, "bgp-router", *tgt,
463 : "bgp-peering", requests);
464 : }
465 : }
466 14600 : }
467 :
468 45891 : static bool ParseInstanceTarget(const string &instance, const xml_node &node,
469 : bool add_change,
470 : BgpConfigParser::RequestList *requests) {
471 45891 : string rtarget(node.child_value());
472 45891 : boost::trim(rtarget);
473 45891 : boost::system::error_code parse_err;
474 45891 : RouteTarget::FromString(rtarget, &parse_err);
475 45891 : assert(!parse_err);
476 :
477 : unique_ptr<autogen::InstanceTargetType> params(
478 45891 : new autogen::InstanceTargetType());
479 45891 : assert(params->XmlParse(node));
480 :
481 45891 : if (add_change) {
482 35286 : MapObjectLinkAttr("routing-instance", instance, "route-target", rtarget,
483 35286 : "instance-target", params.release(), requests);
484 : } else {
485 10605 : MapObjectUnlink("routing-instance", instance, "route-target", rtarget,
486 : "instance-target", requests);
487 : }
488 :
489 45891 : return true;
490 45891 : }
491 :
492 5413 : static bool ParseInstanceVirtualNetwork(const string &instance,
493 : const xml_node &node, bool add_change,
494 : BgpConfigParser::RequestList *requests) {
495 5413 : string vn_name = node.child_value();
496 5413 : if (add_change) {
497 4524 : MapObjectLink("routing-instance", instance,
498 : "virtual-network", vn_name,
499 : "virtual-network-routing-instance", requests);
500 : } else {
501 889 : MapObjectUnlink("routing-instance", instance,
502 : "virtual-network", vn_name,
503 : "virtual-network-routing-instance", requests);
504 : }
505 :
506 5413 : return true;
507 5413 : }
508 :
509 : } // namespace
510 :
511 14664 : BgpConfigParser::BgpConfigParser(DB *db)
512 14664 : : db_(db) {
513 14664 : }
514 :
515 37452 : bool BgpConfigParser::ParseRoutingInstance(const xml_node &parent,
516 : bool add_change,
517 : RequestList *requests) const {
518 37452 : string instance(parent.attribute("name").value());
519 37452 : assert(!instance.empty());
520 :
521 37452 : SessionMap sessions;
522 37452 : list<string> routers;
523 :
524 92259 : for (xml_node node = parent.first_child(); node;
525 54807 : node = node.next_sibling()) {
526 54807 : if (strcmp(node.name(), "bgp-router") == 0) {
527 2252 : string router_name;
528 2252 : ParseBgpRouter(instance, node, add_change, &router_name,
529 : &sessions, requests);
530 2252 : if (!router_name.empty()) {
531 961 : routers.push_back(router_name);
532 : }
533 54807 : } else if (strcmp(node.name(), "vrf-target") == 0) {
534 45891 : ParseInstanceTarget(instance, node, add_change, requests);
535 6664 : } else if (strcmp(node.name(), "virtual-network") == 0) {
536 5413 : ParseInstanceVirtualNetwork(instance, node, add_change, requests);
537 1251 : } else if (strcmp(node.name(), "service-chain-info") == 0) {
538 167 : ParseServiceChain(instance, node, add_change,
539 : "service-chain-information", requests);
540 1084 : } else if (strcmp(node.name(), "ipv6-service-chain-info") == 0) {
541 92 : ParseServiceChain(instance, node, add_change,
542 : "ipv6-service-chain-information", requests);
543 992 : } else if (strcmp(node.name(), "evpn-service-chain-info") == 0) {
544 92 : ParseServiceChain(instance, node, add_change,
545 : "evpn-service-chain-information", requests);
546 900 : } else if (strcmp(node.name(), "evpn-ipv6-service-chain-info") == 0) {
547 92 : ParseServiceChain(instance, node, add_change,
548 : "evpn-ipv6-service-chain-information", requests);
549 808 : } else if (strcmp(node.name(), "route-aggregate") == 0) {
550 346 : ParseInstanceRouteAggregate(instance, node, add_change, requests);
551 462 : } else if (strcmp(node.name(), "routing-policy") == 0) {
552 235 : ParseInstanceRoutingPolicy(instance, node, add_change, requests);
553 227 : } else if (strcmp(node.name(), "static-route-entries") == 0) {
554 67 : ParseStaticRoute(instance, node, add_change, requests);
555 160 : } else if (strcmp(node.name(), "routing-instance-has-pnf") == 0) {
556 96 : ParseInstanceHasPnf(instance, node, add_change, requests);
557 : }
558 : }
559 :
560 37452 : if (add_change) {
561 27118 : BuildPeeringLinks(instance, sessions, requests);
562 : // Generate a full mesh of peering sessions for neighbors that do not
563 : // specify session attributes.
564 27118 : AddNeighborMesh(routers, requests);
565 : } else {
566 10334 : RemovePeeringLinks(instance, sessions, requests);
567 10334 : DeleteNeighborMesh(routers, requests);
568 : }
569 37452 : return true;
570 37452 : }
571 :
572 4593 : bool BgpConfigParser::ParseVirtualNetwork(const xml_node &node,
573 : bool add_change,
574 : RequestList *requests) const {
575 : // vn name
576 4593 : string vn_name(node.attribute("name").value());
577 4593 : assert(!vn_name.empty());
578 :
579 : unique_ptr<autogen::VirtualNetwork::OolProperty> pbb_property(
580 4593 : new autogen::VirtualNetwork::OolProperty);
581 4593 : pbb_property->data = false;
582 :
583 4593 : if (node.attribute("pbb-evpn-enable")) {
584 132 : pbb_property->data =
585 264 : (string(node.attribute("pbb-evpn-enable").value()) == "true");
586 : }
587 :
588 : unique_ptr<autogen::VirtualNetworkType> property(
589 4593 : new autogen::VirtualNetworkType());
590 4593 : assert(property->XmlParse(node));
591 :
592 4593 : if (add_change) {
593 3704 : MapObjectSetProperty("virtual-network", vn_name,
594 3704 : "virtual-network-properties", property.release(), requests);
595 3704 : MapObjectSetProperty("virtual-network", vn_name,
596 3704 : "pbb-evpn-enable", pbb_property.release(), requests);
597 : } else {
598 889 : MapObjectClearProperty("virtual-network", vn_name,
599 : "virtual-network-properties", requests);
600 889 : MapObjectClearProperty("virtual-network", vn_name,
601 : "pbb-evpn-enable", requests);
602 : }
603 :
604 4593 : return true;
605 4593 : }
606 :
607 16 : bool BgpConfigParser::ParseSubCluster(const xml_node &node,
608 : bool add_change,
609 : RequestList *requests) const {
610 16 : string subcluster_name(node.attribute("name").value());
611 16 : assert(!subcluster_name.empty());
612 :
613 : unique_ptr<autogen::SubCluster::StringProperty> subcluster_property(
614 16 : new autogen::SubCluster::StringProperty);
615 :
616 16 : if (node.child("sub-cluster-asn"))
617 16 : subcluster_property->data = string(node.child_value("sub-cluster-asn"));
618 :
619 16 : if (add_change) {
620 16 : MapObjectSetProperty("sub-cluster", subcluster_name,
621 16 : "sub-cluster-asn", subcluster_property.release(), requests);
622 : } else {
623 0 : MapObjectClearProperty("sub-cluster", subcluster_name,
624 : "sub-cluster-asn", requests);
625 : }
626 :
627 : unique_ptr<autogen::SubCluster::NtProperty> id_property(
628 16 : new autogen::SubCluster::NtProperty);
629 16 : if (node.child("sub-cluster-id")) {
630 : std::stringstream sub_cluster_id(
631 0 : string(node.child_value("sub-cluster-id")));
632 0 : sub_cluster_id >> id_property->data;
633 0 : }
634 16 : if (add_change) {
635 16 : MapObjectSetProperty("sub-cluster", subcluster_name,
636 16 : "sub-cluster-id", id_property.release(), requests);
637 : } else {
638 0 : MapObjectClearProperty("sub-cluster", subcluster_name,
639 : "sub-cluster-id", requests);
640 : }
641 16 : return true;
642 16 : }
643 :
644 344 : bool BgpConfigParser::ParseRouteAggregate(const xml_node &node,
645 : bool add_change,
646 : RequestList *requests) const {
647 : // policy name
648 344 : string aggregate_name(node.attribute("name").value());
649 344 : assert(!aggregate_name.empty());
650 :
651 :
652 1032 : for (xml_node child = node.first_child(); child;
653 688 : child = child.next_sibling()) {
654 688 : if (strcmp(child.name(), "aggregate-route-entries") == 0) {
655 344 : if (add_change) {
656 : unique_ptr<autogen::RouteListType>
657 222 : aggregate_routes(new autogen::RouteListType());
658 222 : assert(aggregate_routes->XmlParse(child));
659 222 : MapObjectSetProperty("route-aggregate", aggregate_name,
660 : "aggregate-route-entries",
661 222 : aggregate_routes.release(), requests);
662 222 : } else {
663 122 : MapObjectClearProperty("route-aggregate", aggregate_name,
664 : "aggregate-route-entries", requests);
665 : }
666 344 : } else if (strcmp(child.name(), "nexthop") == 0) {
667 344 : if (add_change) {
668 222 : string nexthop = child.child_value();
669 :
670 : autogen::RouteAggregate::StringProperty *nexthop_property =
671 222 : new autogen::RouteAggregate::StringProperty();
672 222 : nexthop_property->data = nexthop;
673 222 : MapObjectSetProperty("route-aggregate", aggregate_name,
674 : "aggregate-route-nexthop",
675 : nexthop_property, requests);
676 222 : } else {
677 122 : MapObjectClearProperty("route-aggregate", aggregate_name,
678 : "aggregate-route-nexthop", requests);
679 : }
680 : }
681 : }
682 :
683 344 : return true;
684 344 : }
685 :
686 230 : bool BgpConfigParser::ParseRoutingPolicy(const xml_node &node,
687 : bool add_change,
688 : RequestList *requests) const {
689 : // policy name
690 230 : string policy_name(node.attribute("name").value());
691 230 : assert(!policy_name.empty());
692 :
693 : unique_ptr<autogen::PolicyStatementType> policy_statement(
694 230 : new autogen::PolicyStatementType());
695 230 : assert(policy_statement->XmlParse(node));
696 :
697 230 : if (add_change) {
698 187 : MapObjectSetProperty("routing-policy", policy_name,
699 187 : "routing-policy-entries", policy_statement.release(), requests);
700 : } else {
701 43 : MapObjectClearProperty("routing-policy", policy_name,
702 : "routing-policy-entries", requests);
703 : }
704 :
705 230 : return true;
706 230 : }
707 :
708 1137 : bool BgpConfigParser::ParseGlobalSystemConfig(const xml_node &node,
709 : bool add_change,
710 : RequestList *requests) const {
711 2560 : for (xml_node child = node.first_child(); child;
712 1423 : child = child.next_sibling()) {
713 1423 : if (strcmp(child.name(), "graceful-restart-parameters") == 0) {
714 : unique_ptr<autogen::GracefulRestartParametersType> gr_config(
715 697 : new autogen::GracefulRestartParametersType());
716 697 : assert(gr_config->XmlParse(child));
717 :
718 697 : if (add_change) {
719 694 : MapObjectSetProperty("global-system-config", "",
720 : "graceful-restart-parameters",
721 694 : gr_config.release(), requests);
722 : } else {
723 3 : MapObjectClearProperty("global-system-config", "",
724 : "graceful-restart-parameters", requests);
725 : }
726 697 : }
727 1423 : if (strcmp(child.name(), "bgpaas-parameters") == 0) {
728 : unique_ptr<autogen::BGPaaServiceParametersType> bgpaas_config(
729 278 : new autogen::BGPaaServiceParametersType());
730 278 : assert(bgpaas_config->XmlParse(child));
731 :
732 278 : if (add_change) {
733 274 : MapObjectSetProperty("global-system-config", "",
734 274 : "bgpaas-parameters", bgpaas_config.release(), requests);
735 : } else {
736 4 : MapObjectClearProperty("global-system-config", "",
737 : "bgpaas-parameters", requests);
738 : }
739 278 : }
740 1423 : if (strcmp(child.name(), "bgp-always-compare-med") == 0) {
741 : unique_ptr<autogen::GlobalSystemConfig::OolProperty> property(
742 8 : new autogen::GlobalSystemConfig::OolProperty);
743 8 : property->data = (string(child.child_value()) == "true");
744 8 : if (add_change) {
745 5 : MapObjectSetProperty("global-system-config", "",
746 5 : "bgp-always-compare-med", property.release(), requests);
747 : } else {
748 3 : MapObjectClearProperty("global-system-config", "",
749 : "bgp-always-compare-med", requests);
750 : }
751 8 : }
752 1423 : if (strcmp(child.name(), "bgp-all-tags-are-global") == 0) {
753 : unique_ptr<autogen::GlobalSystemConfig::OolProperty> property(
754 5 : new autogen::GlobalSystemConfig::OolProperty);
755 5 : property->data = (string(child.child_value()) == "true");
756 5 : if (add_change) {
757 4 : MapObjectSetProperty("global-system-config", "",
758 4 : "bgp-all-tags-are-global", property.release(), requests);
759 : } else {
760 1 : MapObjectClearProperty("global-system-config", "",
761 : "bgp-all-tags-are-global", requests);
762 : }
763 5 : }
764 1423 : if (strcmp(child.name(), "enable-4byte-as") == 0) {
765 : unique_ptr<autogen::GlobalSystemConfig::OolProperty> property(
766 384 : new autogen::GlobalSystemConfig::OolProperty);
767 384 : property->data = (string(child.child_value()) == "true");
768 384 : if (add_change) {
769 382 : MapObjectSetProperty("global-system-config", "",
770 382 : "enable-4byte-as", property.release(), requests);
771 : } else {
772 2 : MapObjectClearProperty("global-system-config", "",
773 : "enable-4byte-as", requests);
774 : }
775 384 : }
776 1423 : if (strcmp(child.name(), "fast-convergence-parameters") == 0) {
777 : unique_ptr<autogen::FastConvergenceParametersType> property(
778 20 : new autogen::FastConvergenceParametersType());
779 20 : assert(property->XmlParse(child));
780 20 : if (add_change) {
781 19 : MapObjectSetProperty("global-system-config", "",
782 19 : "fast-convergence-parameters", property.release(), requests);
783 : } else {
784 1 : MapObjectClearProperty("global-system-config", "",
785 : "fast-convergence-parameters", requests);
786 : }
787 20 : }
788 1423 : if (strcmp(child.name(), "rd-cluster-seed") == 0) {
789 : unique_ptr<autogen::GlobalSystemConfig::NtProperty> property(
790 27 : new autogen::GlobalSystemConfig::NtProperty);
791 27 : property->data = atoi(child.child_value());
792 27 : if (add_change) {
793 25 : MapObjectSetProperty("global-system-config", "",
794 25 : "rd-cluster-seed", property.release(), requests);
795 : } else {
796 2 : MapObjectClearProperty("global-system-config", "",
797 : "rd-cluster-seed", requests);
798 : }
799 27 : }
800 : }
801 1137 : return true;
802 : }
803 :
804 10 : bool BgpConfigParser::ParseGlobalQosConfig(const xml_node &node,
805 : bool add_change,
806 : RequestList *requests) const {
807 20 : for (xml_node child = node.first_child(); child;
808 10 : child = child.next_sibling()) {
809 10 : if (strcmp(child.name(), "control-traffic-dscp") == 0) {
810 : unique_ptr<autogen::ControlTrafficDscpType> cfg(
811 10 : new autogen::ControlTrafficDscpType());
812 10 : assert(cfg->XmlParse(child));
813 :
814 10 : if (add_change) {
815 9 : MapObjectSetProperty("global-qos-config", "",
816 9 : "control-traffic-dscp", cfg.release(), requests);
817 : } else {
818 1 : MapObjectClearProperty("global-qos-config", "",
819 : "control-traffic-dscp", requests);
820 : }
821 10 : }
822 : }
823 10 : return true;
824 : }
825 :
826 15890 : bool BgpConfigParser::ParseConfig(const xml_node &root, bool add_change,
827 : RequestList *requests) const {
828 15890 : SessionMap sessions;
829 15890 : list<string> routers;
830 :
831 75354 : for (xml_node node = root.first_child(); node; node = node.next_sibling()) {
832 59464 : if (strcmp(node.name(), "bgp-router") == 0) {
833 15650 : string router_name;
834 15650 : ParseBgpRouter(BgpConfigManager::kMasterInstance, node, add_change,
835 : &router_name, &sessions, requests);
836 15650 : if (!router_name.empty()) {
837 5731 : routers.push_back(router_name);
838 : }
839 15650 : }
840 59464 : if (strcmp(node.name(), "routing-instance") == 0) {
841 37452 : ParseRoutingInstance(node, add_change, requests);
842 : }
843 59464 : if (strcmp(node.name(), "virtual-network") == 0) {
844 4593 : ParseVirtualNetwork(node, add_change, requests);
845 : }
846 59464 : if (strcmp(node.name(), "sub-cluster") == 0) {
847 16 : ParseSubCluster(node, add_change, requests);
848 : }
849 59464 : if (strcmp(node.name(), "route-aggregate") == 0) {
850 344 : ParseRouteAggregate(node, add_change, requests);
851 : }
852 59464 : if (strcmp(node.name(), "routing-policy") == 0) {
853 230 : ParseRoutingPolicy(node, add_change, requests);
854 : }
855 59464 : if (strcmp(node.name(), "global-system-config") == 0) {
856 1137 : ParseGlobalSystemConfig(node, add_change, requests);
857 : }
858 59464 : if (strcmp(node.name(), "global-qos-config") == 0) {
859 10 : ParseGlobalQosConfig(node, add_change, requests);
860 : }
861 : }
862 :
863 15890 : if (add_change) {
864 11624 : BuildPeeringLinks(BgpConfigManager::kMasterInstance, sessions,
865 : requests);
866 : // Generate a full mesh of peering sessions for neighbors that do not
867 : // specify session attributes.
868 11624 : AddNeighborMesh(routers, requests);
869 : } else {
870 4266 : RemovePeeringLinks(BgpConfigManager::kMasterInstance, sessions,
871 : requests);
872 4266 : DeleteNeighborMesh(routers, requests);
873 : }
874 :
875 15890 : return true;
876 15890 : }
877 :
878 15890 : bool BgpConfigParser::Parse(const string &content) {
879 15890 : istringstream sstream(content);
880 15890 : xml_document xdoc;
881 15890 : xml_parse_result result = xdoc.load(sstream);
882 15890 : if (result.status == pugi::status_no_document_element) {
883 0 : return true;
884 : }
885 :
886 15890 : if (result.status == pugi::status_ok) {
887 15890 : RequestList requests;
888 31780 : for (xml_node node = xdoc.first_child(); node; node = node.next_sibling()) {
889 15890 : const char *oper = node.name();
890 15890 : assert((strcmp(oper, "config") == 0) || (strcmp(oper, "delete") == 0));
891 15890 : bool add_change = (strcmp(oper, "config") == 0);
892 15890 : assert(ParseConfig(node, add_change, &requests));
893 : }
894 :
895 126350 : while (!requests.empty()) {
896 110460 : unique_ptr<DBRequest> req(requests.front());
897 110460 : requests.pop_front();
898 :
899 : IFMapTable::RequestKey *key =
900 110460 : static_cast<IFMapTable::RequestKey *>(req->key.get());
901 :
902 110460 : IFMapTable *table = IFMapTable::FindTable(db_, key->id_type);
903 110460 : assert(table);
904 110460 : table->Enqueue(req.get());
905 110460 : }
906 :
907 15890 : return true;
908 15890 : }
909 0 : return false;
910 15890 : }
911 :
912 13517 : string BgpConfigParser::session_uuid(const string &left, const string &right,
913 : int index) {
914 : boost::uuids::nil_generator nil;
915 13517 : boost::uuids::name_generator gen(nil());
916 : boost::uuids::uuid uuid;
917 13517 : ostringstream oss;
918 13517 : oss << left << ":" << right << ":" << index;
919 13517 : uuid = gen(oss.str());
920 27034 : return boost::uuids::to_string(uuid);
921 13517 : }
|