LCOV - code coverage report
Current view: top level - ifmap - ifmap_server_parser.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 126 156 80.8 %
Date: 2026-11-09 02:10:49 Functions: 12 13 92.3 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.14