Line data Source code
1 : /* 2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. 3 : */ 4 : 5 : #include <stdint.h> 6 : #include "ifmap/ifmap_server_parser.h" 7 : 8 : #include <pugixml/pugixml.hpp> 9 : #include "db/db.h" 10 : #include "ifmap/ifmap_server_table.h" 11 : #include "ifmap/ifmap_log.h" 12 : #include "ifmap/ifmap_log_types.h" 13 : 14 : using namespace std; 15 : using namespace pugi; 16 : 17 : IFMapServerParser::ModuleMap IFMapServerParser::module_map_; 18 : 19 105 : static const char *NodeName(const xml_node &node) { 20 105 : const char *name = node.name(); 21 : // strip namespace 22 105 : const char *dot = strchr(name, ':'); 23 105 : if (dot != NULL) { 24 66 : name = dot + 1; 25 : } 26 105 : return name; 27 : } 28 : 29 7 : IFMapServerParser *IFMapServerParser::GetInstance(const string &module) { 30 7 : ModuleMap::iterator loc = module_map_.find(module); 31 7 : if (loc != module_map_.end()) { 32 0 : return loc->second; 33 : } 34 7 : IFMapServerParser *parser = new IFMapServerParser(); 35 7 : module_map_.insert(make_pair(module, parser)); 36 7 : return parser; 37 : } 38 : 39 6 : void IFMapServerParser::DeleteInstance(const string &module) { 40 6 : ModuleMap::iterator loc = module_map_.find(module); 41 6 : if (loc == module_map_.end()) { 42 0 : return; 43 : } 44 : 45 6 : delete loc->second; 46 6 : module_map_.erase(loc); 47 : } 48 : 49 27 : void IFMapServerParser::MetadataRegister(const string &metadata, 50 : MetadataParseFn parser) { 51 : pair<MetadataParseMap::iterator, bool> result = 52 27 : metadata_map_.insert(make_pair(metadata, parser)); 53 27 : assert(result.second); 54 27 : } 55 : 56 6 : void IFMapServerParser::MetadataClear(const string &module) { 57 6 : metadata_map_.clear(); 58 6 : DeleteInstance(module); 59 6 : } 60 : 61 15 : static string ParseIdentifier(const xml_node &node) { 62 15 : string id(node.attribute("name").value()); 63 15 : return id; 64 : } 65 : 66 17 : void IFMapServerParser::SetOrigin(struct DBRequest *result) const { 67 : IFMapServerTable::RequestData *data = 68 17 : static_cast<IFMapServerTable::RequestData *>(result->data.get()); 69 17 : data->origin.set_origin(IFMapOrigin::MAP_SERVER); 70 17 : } 71 : 72 17 : bool IFMapServerParser::ParseMetadata(const pugi::xml_node &node, 73 : struct DBRequest *result) const { 74 : IFMapServerTable::RequestData *data = 75 17 : static_cast<IFMapServerTable::RequestData *>(result->data.get()); 76 17 : const char *name = NodeName(node); 77 17 : MetadataParseMap::const_iterator loc = metadata_map_.find(name); 78 17 : if (loc == metadata_map_.end()) { 79 0 : return false; 80 : } 81 17 : std::unique_ptr<AutogenProperty> pvalue; 82 17 : bool success = (loc->second)(node, &pvalue); 83 17 : if (!success) { 84 0 : return false; 85 : } 86 17 : if (data == NULL) { 87 11 : data = new IFMapServerTable::RequestData(); 88 11 : result->data.reset(data); 89 : } 90 17 : data->metadata = name; 91 17 : data->content.reset(pvalue.release()); 92 17 : return true; 93 17 : } 94 : 95 : // Expect the identifier name to be [contrail:]type:name 96 15 : static void IdentifierNsTypeName(const string &id, string *id_type, 97 : string *id_name) { 98 15 : size_t ns = id.find("contrail:"); 99 15 : size_t start = (ns == 0) ? sizeof("contrail:") - 1: 0; 100 15 : size_t loc = id.find(':', start); 101 15 : if (loc != string::npos) { 102 15 : *id_type = string(id, start, loc - start); 103 15 : *id_name = string(id, loc + 1, id.size() - (loc + 1)); 104 : } else { 105 0 : *id_name = id; 106 : } 107 15 : } 108 : 109 4 : static DBRequest *IFMapServerRequestClone(const DBRequest *src) { 110 4 : DBRequest *request = new DBRequest(); 111 4 : request->oper = src->oper; 112 : IFMapTable::RequestKey *src_key = 113 4 : static_cast<IFMapTable::RequestKey *>(src->key.get()); 114 4 : if (src_key != NULL) { 115 : IFMapTable::RequestKey *dst_key = 116 4 : new IFMapTable::RequestKey(); 117 4 : dst_key->id_type = src_key->id_type; 118 4 : dst_key->id_name = src_key->id_name; 119 4 : request->key.reset(dst_key); 120 : } 121 : 122 : IFMapServerTable::RequestData *src_data = 123 4 : static_cast<IFMapServerTable::RequestData *>(src->data.get()); 124 4 : if (src_data) { 125 : IFMapServerTable::RequestData *dst_data = 126 4 : new IFMapServerTable::RequestData(); 127 4 : dst_data->id_type = src_data->id_type; 128 4 : dst_data->id_name = src_data->id_name; 129 4 : request->data.reset(dst_data); 130 : } 131 4 : return request; 132 : } 133 : 134 13 : bool IFMapServerParser::ParseResultItem( 135 : const xml_node &parent, bool add_change, RequestList *list) const { 136 13 : unique_ptr<DBRequest> request(new DBRequest); 137 13 : request->oper = (add_change ? DBRequest::DB_ENTRY_ADD_CHANGE : 138 : DBRequest::DB_ENTRY_DELETE); 139 13 : IFMapTable::RequestKey *key = NULL; 140 13 : IFMapServerTable::RequestData *data = NULL; 141 13 : int idcount = 0; 142 13 : bool has_meta = false; 143 41 : for (xml_node node = parent.first_child(); node; 144 28 : node = node.next_sibling()) { 145 28 : const char *name = NodeName(node); 146 28 : if (strcmp(name, "identity") == 0) { 147 15 : string id = ParseIdentifier(node); 148 15 : switch (idcount) { 149 13 : case 0: 150 13 : key = new IFMapTable::RequestKey(); 151 13 : request->key.reset(key); 152 13 : IdentifierNsTypeName(id, &key->id_type, &key->id_name); 153 13 : break; 154 2 : case 1: 155 2 : data = new IFMapServerTable::RequestData(); 156 2 : request->data.reset(data); 157 2 : IdentifierNsTypeName(id, &data->id_type, &data->id_name); 158 2 : break; 159 0 : default: 160 0 : return false; 161 : } 162 15 : idcount++; 163 15 : continue; 164 15 : } 165 13 : if (strcmp(name, "metadata") == 0) { 166 13 : if (has_meta) { 167 0 : return false; 168 : } 169 13 : has_meta = true; 170 30 : for (xml_node meta = node.first_child(); meta; 171 17 : meta = meta.next_sibling()) { 172 17 : if (ParseMetadata(meta, request.get())) { 173 17 : SetOrigin(request.get()); 174 17 : DBRequest *current = request.release(); 175 17 : if (meta.next_sibling()) { 176 4 : request.reset(IFMapServerRequestClone(current)); 177 : } 178 17 : list->push_back(current); 179 : } 180 : } 181 : } 182 : } 183 : 184 13 : if (idcount == 0 || !has_meta) { 185 0 : return false; 186 : } 187 13 : return true; 188 13 : } 189 : 190 5 : void IFMapServerParser::ParseResults( 191 : const xml_document &xdoc, RequestList *list) const { 192 5 : xml_node current = xdoc.first_child(); 193 25 : while (current) { 194 : bool add_change; 195 20 : if (strcmp(NodeName(current), "updateResult") == 0 || 196 35 : strcmp(NodeName(current), "searchResult") == 0 || 197 15 : strcmp(NodeName(current), "deleteResult") == 0) { 198 : 199 5 : if (strcmp(NodeName(current), "deleteResult") == 0) { 200 0 : add_change = false; 201 : } else { 202 5 : add_change = true; 203 : } 204 5 : xml_node result = current; 205 18 : for (xml_node node = result.first_child(); node; 206 13 : node = node.next_sibling()) { 207 13 : ParseResultItem(node, add_change, list); 208 : } 209 5 : current = current.next_sibling(); 210 : } else { 211 15 : current = current.first_child(); 212 : } 213 : } 214 5 : } 215 : 216 : // Called in the context of the ifmap client thread. 217 0 : bool IFMapServerParser::Receive(DB *db, const char *data, size_t length, 218 : uint64_t sequence_number) { 219 0 : xml_document xdoc; 220 0 : pugi::xml_parse_result result = xdoc.load_buffer(data, length); 221 0 : if (!result) { 222 0 : IFMAP_WARN(IFMapXmlLoadError, "Unable to load XML document", length); 223 0 : return false; 224 : } 225 : 226 0 : IFMapServerParser::RequestList requests; 227 0 : ParseResults(xdoc, &requests); 228 : 229 0 : while (!requests.empty()) { 230 0 : unique_ptr<DBRequest> req(requests.front()); 231 0 : requests.pop_front(); 232 : 233 : IFMapTable::RequestKey *key = 234 0 : static_cast<IFMapTable::RequestKey *>(req->key.get()); 235 0 : key->id_seq_num = sequence_number; 236 : 237 0 : IFMapTable *table = IFMapTable::FindTable(db, key->id_type); 238 0 : if (table != NULL) { 239 0 : table->Enqueue(req.get()); 240 : } else { 241 0 : IFMAP_TRACE(IFMapTblNotFoundTrace, "Cant find table", key->id_type); 242 : } 243 0 : } 244 0 : return true; 245 0 : }