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 "ifmap/ifmap_encoder.h" 7 : 8 : #include <sstream> 9 : #include "ifmap/ifmap_link.h" 10 : #include "ifmap/ifmap_object.h" 11 : #include "ifmap/ifmap_update.h" 12 : 13 : using namespace pugi; 14 : using namespace std; 15 : 16 585 : IFMapMessage::IFMapMessage() : op_type_(NONE), node_count_(0), 17 195 : objects_per_message_(kObjectsPerMessage) { 18 : // init empty document 19 195 : Open(); 20 195 : } 21 : 22 309 : void IFMapMessage::Open() { 23 309 : xml_node iq = doc_.append_child("iq"); 24 : // set iq (type, from, to) attributes 25 309 : iq.append_attribute("type") = "set"; 26 309 : iq.append_attribute("from") = "network-control@contrailsystems.com"; 27 309 : iq.append_attribute("to") = ""; 28 309 : config_ = iq.append_child("config"); 29 309 : } 30 : 31 116 : void IFMapMessage::Close() { 32 116 : ostringstream oss; 33 116 : doc_.save(oss); 34 116 : str_ = oss.str(); 35 116 : } 36 : 37 116 : void IFMapMessage::SetReceiverInMsg(const std::string &cli_identifier) { 38 116 : xml_node iq = doc_.child("iq"); 39 116 : assert(iq); 40 116 : xml_attribute iqattr = iq.attribute("to"); 41 116 : assert(iqattr); 42 116 : std::string str(cli_identifier); 43 116 : str += "/config"; 44 116 : iqattr.set_value(str.c_str()); 45 116 : } 46 : 47 0 : void IFMapMessage::SetObjectsPerMessage(int num) { 48 0 : objects_per_message_ = num; 49 0 : } 50 : 51 890 : void IFMapMessage::EncodeUpdate(const IFMapUpdate *update) { 52 : // update is either of type UPDATE OR DELETE 53 890 : if (update->IsUpdate()) { 54 890 : if (op_type_ != UPDATE) { 55 114 : op_node_ = config_.append_child("update"); 56 114 : op_type_ = UPDATE; 57 : } 58 890 : if (update->data().type == IFMapObjectPtr::NODE) { 59 432 : EncodeNode(update); 60 458 : } else if (update->data().type == IFMapObjectPtr::LINK) { 61 458 : EncodeLink(update); 62 : } else { 63 0 : assert(0); 64 : } 65 : } else { 66 0 : if (op_type_ != DEL) { 67 0 : op_node_ = config_.append_child("delete"); 68 0 : op_type_ = DEL; 69 : } 70 0 : if (update->data().type == IFMapObjectPtr::NODE) { 71 0 : EncodeNode(update); 72 0 : } else if (update->data().type == IFMapObjectPtr::LINK) { 73 0 : EncodeLink(update); 74 : } else { 75 0 : assert(0); 76 : } 77 : } 78 890 : node_count_++; 79 890 : } 80 : 81 432 : void IFMapMessage::EncodeNode(const IFMapUpdate *update) { 82 432 : IFMapNode *node = update->data().u.node; 83 432 : if (update->IsUpdate()) { 84 432 : node->EncodeNodeDetail(&op_node_); 85 : } else { 86 0 : node->EncodeNode(&op_node_); 87 : } 88 432 : } 89 : 90 458 : void IFMapMessage::EncodeLink(const IFMapUpdate *update) { 91 458 : xml_node link_node = op_node_.append_child("link"); 92 : 93 458 : const IFMapLink *link = update->data().u.link; 94 : 95 458 : IFMapNode::EncodeNode(link->left_id(), &link_node); 96 458 : IFMapNode::EncodeNode(link->right_id(), &link_node); 97 458 : link->EncodeLinkInfo(&link_node); 98 : 99 458 : node_count_++; 100 458 : } 101 : 102 890 : bool IFMapMessage::IsFull() { 103 890 : return ((node_count_ >= objects_per_message_) ? true : false); 104 : } 105 : 106 172 : bool IFMapMessage::IsEmpty() { 107 172 : return ((node_count_ == 0) ? true : false); 108 : } 109 : 110 : // 111 : // Reset the IFMapMessage to initial state so that it can be used to build 112 : // the next config message. 113 : // 114 : // Using remove_child to remove the only child of the document is a better 115 : // way to clear the document than using reset. The pugixml library allocates 116 : // memory for a document in increments of 32KB pages and then manages smaller 117 : // allocations (nodes or attributes) using these pages. Calling reset method 118 : // on a document frees all the pages. In contrast, removing the only child 119 : // node of the document returns the smaller allocations to the free pool of 120 : // memory for the document, but doesn't free the pages themselves. This lets 121 : // the library reuse the same memory when building the tree for each message. 122 : // 123 114 : void IFMapMessage::Reset() { 124 114 : doc_.remove_child("iq"); 125 114 : node_count_ = 0; 126 114 : op_type_ = NONE; 127 114 : Open(); 128 114 : }