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