Added quantiling UDAFs
[com/gs-lite.git] / src / ftacmp / iface_q.cc
1 /* ------------------------------------------------\r
2 Copyright 2014 AT&T Intellectual Property\r
3    Licensed under the Apache License, Version 2.0 (the "License");\r
4    you may not use this file except in compliance with the License.\r
5    You may obtain a copy of the License at\r
6 \r
7      http://www.apache.org/licenses/LICENSE-2.0\r
8 \r
9    Unless required by applicable law or agreed to in writing, software\r
10    distributed under the License is distributed on an "AS IS" BASIS,\r
11    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
12    See the License for the specific language governing permissions and\r
13    limitations under the License.\r
14  ------------------------------------------- */\r
15 #include "iface_q.h"\r
16 #include<errno.h>\r
17 #include <unistd.h>\r
18 #include <algorithm>\r
19 #include <cctype>\r
20 \r
21 \r
22 using namespace std;\r
23 \r
24 extern string hostname;         // namne of the current host\r
25 \r
26 static string int_to_string(int i){\r
27     string ret;\r
28     char tmpstr[100];\r
29     sprintf(tmpstr,"%d",i);\r
30     ret=tmpstr;\r
31     return(ret);\r
32 }\r
33 \r
34 \r
35 //              Interface for the res parser\r
36 extern int ResParserparse(void);\r
37 extern FILE *ResParserin;\r
38 extern int ResParserdebug;\r
39 void ResParser_setfileinput(FILE *f);\r
40 void ResParser_setstringinput(char *s);\r
41 extern int flex_res_lineno;\r
42 \r
43 resparse_data *rpd_ptr;\r
44 vector<string> res_val_vec, res_attr_vec;\r
45 string res_a, res_v;\r
46 \r
47 ///////////////////////////////////////\r
48 ///             iface_t methods\r
49 \r
50         void iface_t::add_property(const char *name, const char *att){\r
51                 string nm(name);\r
52                 std::transform(nm.begin(), nm.end(), nm.begin(), (int(*)(int))std::tolower);\r
53                 vals[nm].push_back(att);\r
54         }\r
55 \r
56         void iface_t::add_property(const char *name, const char **atts){\r
57                 string val = "";\r
58                 string nm = name;\r
59                 std::transform(nm.begin(), nm.end(), nm.begin(), (int(*)(int))std::tolower);\r
60                 if(atts[0]) val = atts[1];\r
61 \r
62                 vals[nm].push_back(val);\r
63         }\r
64 \r
65         void iface_t::add_property(const char *name, vector<string> &val_vec){\r
66                 string val = "";\r
67                 string nm = name;\r
68                 std::transform(nm.begin(), nm.end(), nm.begin(), (int(*)(int))std::tolower);\r
69                 if(val_vec.size()) val = val_vec[0];\r
70 \r
71                 vals[nm].push_back(val);\r
72         }\r
73 \r
74         int iface_t::finalize(string &errs){\r
75                 string tag ="ERROR in interface starting at line "+int_to_string(lineno)+", ";\r
76                 string e;\r
77                 if(vals.count("name") == 0){\r
78                         e += "Name not specified. ";\r
79                 }else{\r
80                         if(vals["name"].size() > 1){\r
81                                 e+="More than one name specified. ";\r
82                         }\r
83                 }\r
84 \r
85                 if(e != ""){\r
86                         errs += tag + e + "\n";\r
87                         return(1);\r
88                 }\r
89                 return(0);\r
90         }\r
91 \r
92         string iface_t::to_string(){\r
93                 int i;\r
94                 string ret = "Interface "+vals["name"][0]+":\n";\r
95                 map<string, vector<string> >::iterator svmi;\r
96                 for(svmi=vals.begin();svmi!=vals.end();++svmi){\r
97                         ret += "\t"+(*svmi).first + " : ";\r
98                         for(i=0;i<((*svmi).second).size();++i){\r
99                                 if(i>0) ret+=", ";\r
100                                 ret += (*svmi).second[i];\r
101                         }\r
102                         ret += "\n";\r
103                 }\r
104 \r
105                 return ret;\r
106         }\r
107 \r
108         string iface_t::get_name(){\r
109                 if(vals.count("name") == 0) return (string)"";\r
110                 return (vals["name"])[0];\r
111         }\r
112 \r
113         string iface_t::get_host(){\r
114                 if(vals.count("host") == 0) return (string)"";\r
115                 return (vals["host"])[0];\r
116         }\r
117 \r
118 \r
119         bool iface_t::eval_Contains(string prop, string val){\r
120                 // convert to lowercase\r
121                 std::transform(prop.begin(), prop.end(), prop.begin(), (int(*)(int))std::tolower);\r
122 \r
123                 if(vals.count(prop) == 0) return false;\r
124                 int i;\r
125                 for(i=0;i<vals[prop].size();++i){\r
126                         if((vals[prop])[i] == val) return true;\r
127                 }\r
128                 return false;\r
129         }\r
130 \r
131         bool iface_t::eval_Equals(string prop, string val){\r
132                 // convert to lowercase\r
133                 std::transform(prop.begin(), prop.end(), prop.begin(), (int(*)(int))std::tolower);\r
134                 if(vals.count(prop) == 0) return false;\r
135                 if(vals[prop].size() != 1) return false;\r
136                 int i;\r
137                 for(i=0;i<vals[prop].size();++i){\r
138                         if((vals[prop])[i] == val) return true;\r
139                 }\r
140                 return false;\r
141         }\r
142 \r
143         bool iface_t::eval_Exists(string prop){\r
144                 // convert to lowercase\r
145                 std::transform(prop.begin(), prop.end(), prop.begin(), (int(*)(int))std::tolower);\r
146                 if(vals.count(prop) == 0) return false;\r
147                 return true;\r
148         }\r
149 \r
150 \r
151 ///////////////////////////////////////\r
152 ///             gs_host_t methods\r
153 \r
154         void gs_host_t::add_property(const char *name, const char *att){\r
155                 string nm(name);\r
156                 std::transform(nm.begin(), nm.end(), nm.begin(), (int(*)(int))std::tolower);\r
157                 vals[nm].push_back(att);\r
158         }\r
159 \r
160         void gs_host_t::add_property(const char *name, vector<string> &val_vec){\r
161                 string val = "";\r
162                 string nm = name;\r
163                 std::transform(nm.begin(), nm.end(), nm.begin(), (int(*)(int))std::tolower);\r
164                 if(val_vec.size()) val = val_vec[0];\r
165 \r
166                 vals[nm].push_back(val);\r
167         }\r
168 \r
169         int gs_host_t::finalize(string &errs){\r
170                 string tag ="ERROR in host starting at line "+int_to_string(lineno)+", ";\r
171                 string e;\r
172                 if(vals.count("name") == 0){\r
173                         e += "Name not specified. ";\r
174                 }else{\r
175                         if(vals["name"].size() > 1){\r
176                                 e+="More than one name specified. ";\r
177                         }\r
178                 }\r
179 \r
180                 if(e != ""){\r
181                         errs += tag + e + "\n";\r
182                         return(1);\r
183                 }\r
184                 return(0);\r
185         }\r
186 \r
187 \r
188 /////////////////////////////////////////////////////////////////\r
189 ///             reparse_data methods\r
190 \r
191         int resparse_data::finalize_iface(string &errs){\r
192                 int ret = curr_iface->finalize(errs);\r
193                 if(ret) {\r
194                         delete curr_iface;\r
195                         failure = true;\r
196                 }else{\r
197                         curr_host->add_interface(curr_iface);\r
198                 }\r
199                 return ret;\r
200         }\r
201 \r
202 \r
203         int resparse_data::finalize_host(string &errs){\r
204                 int ret = curr_host->finalize(errs);\r
205                 if(ret) {\r
206                         delete curr_host;\r
207                         failure = true;\r
208                 }else{\r
209 \r
210                         string host = curr_host->vals["name"][0];\r
211                         // in non-distributed case we will ignore all other hosts\r
212                         if (!distributed_mode) {\r
213                                 char buf[1000];\r
214                                 if (host != hostname)\r
215                                         return ret;\r
216                         }\r
217                         // we need to exclude failed hosts\r
218                         if (!use_live_hosts_file || live_hosts->count(hostname)) {\r
219                                 hosts.push_back(curr_host);\r
220 \r
221                                 // push the host name to every interface\r
222                                 curr_host->propagate_name();\r
223 \r
224                                 // add all interfaces into interface list\r
225                                 for(int i=0;i<curr_host->ifaces.size();i++)\r
226                                         ifaces.push_back(curr_host->ifaces[i]);\r
227                         }\r
228                 }\r
229                 return ret;\r
230         }\r
231 \r
232         string resparse_data::to_string(){\r
233                 string ret;\r
234                 int i;\r
235                 for(i=0;i<ifaces.size();i++)\r
236                         ret += ifaces[i]->to_string();\r
237                 return ret;\r
238         }\r
239 \r
240         vector<pair<string,string> > resparse_data::find_ifaces(predicate_t *pr){\r
241                 int i;\r
242                 vector<pair<string,string> > ret;\r
243                 for(i=0;i<ifaces.size();++i){\r
244                         if(this->eval_pred(i,pr)){\r
245                                 pair<string,string> p(ifaces[i]->get_host(), ifaces[i]->get_name());\r
246                                 ret.push_back(p);\r
247                         }\r
248                 }\r
249                 return ret;\r
250         }\r
251 \r
252 \r
253         vector<int> resparse_data::get_ifaces_by_Name(std::string host_name, std::string if_name){\r
254                 int i;\r
255                 vector<int> ret;\r
256                 for(i=0;i<ifaces.size();++i){\r
257                         if(ifaces[i]->get_host() == host_name && ifaces[i]->get_name() == if_name)\r
258                                 ret.push_back(i);\r
259 \r
260                 }\r
261                 return ret;\r
262         }\r
263 \r
264 \r
265         bool resparse_data::eval_pred(int i, predicate_t *pr){\r
266     vector<scalarexp_t *> op_list;\r
267         string prop, val;\r
268 \r
269         switch(pr->get_operator_type()){\r
270         case PRED_IN:\r
271                 fprintf(stderr,"INTERNAL ERROR in reparse_date::eval_pred, line %d, character %d, IN not supported. %d\n",\r
272                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
273                 exit(1);\r
274         case PRED_COMPARE:\r
275                 fprintf(stderr,"INTERNAL ERROR in reparse_date::eval_pred, line %d, character %d, IN not supported. %d\n",\r
276                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
277                 exit(1);\r
278         case PRED_UNARY_OP:\r
279                 if(pr->get_op() == "NOT")\r
280                         return(! eval_pred(i, pr->get_left_pr()) );\r
281                 fprintf(stderr,"INTERNAL ERROR in reparse_date::eval_pred, line %d, character %d, unknown unary pred operator %s.\n",\r
282                         pr->get_lineno(), pr->get_charno(), pr->get_op().c_str() );\r
283                 exit(1);\r
284         case PRED_BINARY_OP:\r
285                 if(pr->get_op() == "AND"){\r
286                         if(! eval_pred(i, pr->get_left_pr()) ) return false;\r
287                         return  eval_pred(i, pr->get_right_pr()) ;\r
288                 }\r
289                 if(pr->get_op() == "OR"){\r
290                         if( eval_pred(i, pr->get_left_pr()) ) return true;\r
291                         return  eval_pred(i, pr->get_right_pr()) ;\r
292                 }\r
293                 fprintf(stderr,"INTERNAL ERROR in reparse_date::eval_pred, line %d, character %d, unknown binary pred operator %s.\n",\r
294                         pr->get_lineno(), pr->get_charno(), pr->get_op().c_str() );\r
295                 exit(1);\r
296         case PRED_FUNC:\r
297                 op_list = pr->get_op_list();\r
298                 if(op_list[0]->get_operator_type() != SE_PARAM){\r
299                         fprintf(stderr,"INTERNAL ERROR : ifq parameters are supposed to be of type SE_PARAM, found %s at position 0\n",op_list[0]->get_op().c_str());\r
300                         exit(1);\r
301                 }else{\r
302                         prop=op_list[0]->get_op();\r
303                 }\r
304                 if(op_list.size() > 1){\r
305                         if(op_list[1]->get_operator_type() != SE_PARAM){\r
306                                 fprintf(stderr,"INTERNAL ERROR : ifq parameters are supposed to be of type SE_PARAM, found %s at position 1\n",op_list[0]->get_op().c_str());\r
307                                 exit(1);\r
308                         }else{\r
309                                 val=op_list[1]->get_op();\r
310                         }\r
311                 }\r
312 \r
313                 if(pr->get_op() == "Contains"){\r
314                         if(op_list.size() != 2){\r
315                                 fprintf(stderr,"INTERNAL ERROR : predicate Contains expects 2 parameters, received %lu\n",op_list.size());\r
316                                 exit(1);\r
317                         }\r
318                         return ifaces[i]->eval_Contains(prop,val);\r
319                 }\r
320 \r
321                 if(pr->get_op() == "Equals"){\r
322                         if(op_list.size() != 2){\r
323                                 fprintf(stderr,"INTERNAL ERROR : predicate Equals expects 2 parameters, received %lu\n",op_list.size());\r
324                                 exit(1);\r
325                         }\r
326                         return ifaces[i]->eval_Equals(prop,val);\r
327                 }\r
328 \r
329                 if(pr->get_op() == "Exists"){\r
330                         if(op_list.size() != 1){\r
331                                 fprintf(stderr,"INTERNAL ERROR : predicate Exists expects 1 parameter, received %lu\n",op_list.size());\r
332                                 exit(1);\r
333                         }\r
334                         return ifaces[i]->eval_Exists(prop);\r
335                 }\r
336 \r
337                 fprintf(stderr,"INTERNAL ERROR : Unknown predicate %s in reparse_date::eval_pred.\n",pr->get_op().c_str());\r
338                 exit(1);\r
339 \r
340         default:\r
341                 fprintf(stderr,"INTERNAL ERROR in reparse_date::eval_pred, line %d, character %d, unknown predicate operator type %d\n",\r
342                         pr->get_lineno(), pr->get_charno(), pr->get_operator_type() );\r
343                 exit(1);\r
344         }\r
345 \r
346         return(false);\r
347 \r
348         }\r
349 \r
350 \r
351 ///////////////////////////////////////////\r
352 ///             XML parser callbacks for parsing interface resources\r
353 \r
354 void startElement(void *userData, const char *name, const char **atts) {\r
355   int i;\r
356 \r
357   resparse_data *rpd = (resparse_data *)userData;\r
358   rpd->level.push_back(name);\r
359 \r
360   if(rpd->level.size() == 1 && rpd->level[0] == "Resources")\r
361         rpd->in_Resources = true;\r
362 \r
363   if(rpd->in_Resources && rpd->level.size() == 2 && rpd->level[1] == "Interface"){\r
364 //      rpd->new_iface(XML_GetCurrentLineNumber(rpd->parser));\r
365         rpd->new_iface(1);\r
366     rpd->in_Iface = true;\r
367   }\r
368 \r
369   if(rpd->in_Iface && rpd->level.size() == 3){\r
370         rpd->add_property(name, atts);\r
371   }\r
372 \r
373 \r
374 //  for(i=0;i<rpd->level.size();++i) printf("%s, ",rpd->level[i].c_str());\r
375 //  printf("\n");\r
376 }\r
377 \r
378 void startElement(void *userData, const char *name, vector<string> &attr_vec, vector<string> &val_vec){\r
379   int i;\r
380 \r
381   resparse_data *rpd = (resparse_data *)userData;\r
382   rpd->level.push_back(name);\r
383 \r
384   if(rpd->level.size() == 1 && rpd->level[0] == "Resources")\r
385         rpd->in_Resources = true;\r
386 \r
387   if(rpd->in_Resources && rpd->level.size() == 2 && rpd->level[1] == "Host"){\r
388 //      rpd->new_iface(XML_GetCurrentLineNumber(rpd->parser));\r
389 \r
390         rpd->new_host(flex_res_lineno);\r
391         for (int i = 0; i < attr_vec.size(); ++i)\r
392                 rpd->curr_host->add_property(attr_vec[i].c_str(), val_vec[i].c_str());\r
393     rpd->in_Host = true;\r
394   }\r
395 \r
396   if(rpd->in_Host && rpd->level.size() == 3) {\r
397           if ( rpd->level[2] == "Interface"){\r
398                 //      rpd->new_iface(XML_GetCurrentLineNumber(rpd->parser));\r
399                 rpd->new_iface(flex_res_lineno);\r
400                 for (int i = 0; i < attr_vec.size(); ++i)\r
401                         rpd->add_property(attr_vec[i].c_str(), val_vec[i].c_str());\r
402                 rpd->in_Iface = true;\r
403           } else {\r
404                 rpd->curr_host->add_property(name, val_vec);\r
405           }\r
406         }\r
407 \r
408   if(rpd->in_Iface && rpd->level.size() == 4){\r
409         rpd->add_property(name, val_vec);\r
410   }\r
411 \r
412 \r
413 //  for(i=0;i<rpd->level.size();++i) printf("%s, ",rpd->level[i].c_str());\r
414 //  printf("\n");\r
415 }\r
416 \r
417 \r
418 void endElement(void *userData, const char *name) {\r
419   resparse_data *rpd = (resparse_data *)userData;\r
420 \r
421   if(rpd->in_Iface && rpd->level.size() == 3){\r
422         string err_msg;\r
423         int err = rpd->finalize_iface(err_msg);\r
424         if(err) fprintf(stderr,"%s\n",err_msg.c_str());\r
425   } else if (rpd->in_Host && rpd->level.size() == 2) {\r
426         string err_msg;\r
427         int err = rpd->finalize_host(err_msg);\r
428         if(err) fprintf(stderr,"%s\n",err_msg.c_str());\r
429   }\r
430 \r
431   rpd->level.pop_back();\r
432 }\r
433 \r
434 \r
435 //              Interface to ifq definition lexer and parser ...\r
436 \r
437 extern int IfqParserparse(void);\r
438 extern FILE *IfqParserin;\r
439 extern int IfqParserdebug;\r
440 void IfqParser_setfileinput(FILE *f);\r
441 void IfqParser_setstringinput(char *s);\r
442 \r
443 \r
444 fta_parse_t *ifq_parse_result;\r
445 \r
446 int ifq_t::load_ifaces(string fname, bool use_live_hosts_file, bool disributed_mode, string &err){\r
447   char buf[1000], errbuf[1000];\r
448 //  XML_Parser parser = XML_ParserCreate(NULL);\r
449 \r
450   int done;\r
451   int depth = 0;\r
452   err="";\r
453 \r
454   // open the list of failed hosts\r
455   set<string> live_hosts;\r
456   if (use_live_hosts_file) {\r
457           FILE* live_hosts_file = fopen("live_hosts.txt", "r");\r
458           if (!live_hosts_file) {\r
459                 err="Error, can't open live_hosts.txt, error is ";\r
460                 err+=strerror(errno); err+="\n";\r
461                 return(1);\r
462           }\r
463 \r
464           while(fgets(buf, 1000, live_hosts_file)) {\r
465                   char* host = strtok(buf, " \t\n\r");  // strip the line\r
466                   if (host)\r
467                           live_hosts.insert(host);\r
468           }\r
469 \r
470           fclose(live_hosts_file);\r
471   }\r
472 \r
473 \r
474 \r
475 // IfqParserdebug = 1;\r
476 \r
477   FILE *resfile = fopen(fname.c_str(),"r");\r
478   if(resfile == NULL){\r
479         err="Error, can't open "+fname+", error is ";\r
480         err+=strerror(errno); err+="\n";\r
481         return(1);\r
482   }\r
483 \r
484 //  rpd = new resparse_data(parser);\r
485   rpd = new resparse_data(use_live_hosts_file, &live_hosts, disributed_mode);\r
486   rpd_ptr = rpd;\r
487 \r
488   ResParser_setfileinput(resfile);\r
489   if(ResParserparse()){\r
490         err = "ERROR, interface query parse failed.\n";\r
491         return(1);\r
492   }\r
493 \r
494 /*\r
495   XML_SetUserData(parser, rpd);\r
496   XML_SetElementHandler(parser, startElement, endElement);\r
497   do {\r
498     size_t len = fread(buf, 1, sizeof(buf), resfile);\r
499     done = len < sizeof(buf);\r
500     if (!XML_Parse(parser, buf, len, done)) {\r
501       sprintf(errbuf,\r
502               "%s at line %d\n",\r
503               XML_ErrorString(XML_GetErrorCode(parser)),\r
504               XML_GetCurrentLineNumber(parser));\r
505                 err=errbuf;\r
506       return 1;\r
507     }\r
508   } while (!done);\r
509   XML_ParserFree(parser);\r
510 \r
511   if(rpd->failed()){\r
512         err = "Interface resource parse failed, exiting.\n";\r
513   }\r
514 */\r
515 \r
516   fclose(resfile);\r
517 \r
518   return(0);\r
519 \r
520 }\r
521 \r
522 int ifq_t::load_ifqs(string fname, string &err){\r
523   char err_buf[1000];\r
524   err="";\r
525 \r
526   FILE *qfile = fopen(fname.c_str(),"r");\r
527   if(qfile == NULL){\r
528         sprintf(err_buf, "ERROR, can't open %s, error is %s\n",fname.c_str(),strerror(errno));\r
529         err=err_buf;\r
530         return(1);\r
531   }\r
532 \r
533   ifq_parse_result = new fta_parse_t();\r
534   IfqParser_setfileinput(qfile);\r
535   if(IfqParserparse()){\r
536         err = "ERROR, interface query parse failed.\n";\r
537         return(1);\r
538   }\r
539 \r
540   vector<table_exp_t *> ifqlist = ifq_parse_result->parse_tree_list->qlist;\r
541   int i;\r
542   bool dup = false;\r
543   for(i=0;i<ifqlist.size();++i){\r
544         string nm = ifqlist[i]->nmap["name"];\r
545         if(ifq_map.count(nm)){\r
546                 err += "ERROR, Duplicate interface query "+nm+"\n";\r
547                 dup = true;\r
548         }\r
549         ifq_map[nm] = ifqlist[i]->wh;\r
550   }\r
551 \r
552 \r
553   if(dup) return(1);\r
554   return(0);\r
555 }\r
556 \r
557 \r
558 vector<pair<string,string> > ifq_t::eval(string qname, int &err_no){\r
559         vector<pair<string,string> > retval;\r
560         err_no = 0;\r
561 \r
562         if(ifq_map.count(qname) == 0){\r
563                 err_no = 1;\r
564                 return retval;\r
565         }\r
566         if(rpd->failed()){\r
567                 err_no = 2;\r
568                 return retval;\r
569         }\r
570 \r
571         return rpd->find_ifaces(ifq_map[qname]);\r
572 \r
573 }\r
574 \r
575 vector<string> ifq_t::get_iface_vals(string host_name, string basic_if_name, string property, int &err_no, string &err_str){\r
576         vector<string> retval;\r
577         err_no = 0;\r
578 \r
579         char *cdat = strdup(basic_if_name.c_str());\r
580         int pos;\r
581         string virtual_iface = "0";\r
582         string iface_name = basic_if_name;\r
583         for(pos=strlen(cdat)-1;pos>=0 && isdigit(cdat[pos]);--pos);\r
584         if(pos>0 && cdat[pos] == 'X' && pos<=strlen(cdat)-2){\r
585                 cdat[pos] = '\0';\r
586                 virtual_iface = cdat+pos+1;\r
587                 iface_name = cdat;\r
588         }\r
589         free(cdat);\r
590 \r
591         if(property == "virtual_interface_id"){\r
592                 retval.push_back(virtual_iface);\r
593                 return retval;\r
594         }\r
595 \r
596 \r
597         if(rpd->failed()){\r
598                 err_no = 1; err_str = "interface resource parse failed.";\r
599                 return retval;\r
600         }\r
601 \r
602         vector<int> ifi = rpd->get_ifaces_by_Name(host_name, iface_name);\r
603         if(ifi.size() == 0){\r
604                 err_no = 1; err_str="interface not found.";\r
605                 return retval;\r
606         }\r
607         if(ifi.size()>1){\r
608                 err_no = 1; err_str="multiple interfaces found.";\r
609                 return retval;\r
610         }\r
611 \r
612         return rpd->get_property(ifi[0], property);\r
613 \r
614 }\r
615 \r
616 vector<string> ifq_t::get_iface_properties(string host_name, string basic_if_name, int &err_no, string &err_str){\r
617         vector<string> retval;\r
618         err_no = 0;\r
619 \r
620         char *cdat = strdup(basic_if_name.c_str());\r
621         int pos;\r
622         string virtual_iface = "0";\r
623         string iface_name = basic_if_name;\r
624         for(pos=strlen(cdat)-1;pos>=0 && isdigit(cdat[pos]);--pos);\r
625         if(pos>0 && cdat[pos] == 'X' && pos<=strlen(cdat)-2){\r
626                 cdat[pos] = '\0';\r
627                 virtual_iface = cdat+pos+1;\r
628                 iface_name = cdat;\r
629         }\r
630         free(cdat);\r
631 \r
632         if(rpd->failed()){\r
633                 err_no = 1; err_str = "interface resource parse failed.";\r
634                 return retval;\r
635         }\r
636 \r
637         vector<int> ifi = rpd->get_ifaces_by_Name(host_name, iface_name);\r
638         if(ifi.size() == 0){\r
639                 err_no = 1; err_str="interface not found.";\r
640                 return retval;\r
641         }\r
642         if(ifi.size()>1){\r
643                 err_no = 1; err_str="multiple interfaces found.";\r
644                 return retval;\r
645         }\r
646 \r
647         return rpd->get_properties(ifi[0]);\r
648 \r
649 }\r