Skip to content

Commit 15ef685

Browse files
authored
Add option to generate current dep graph to saidump (sonic-net#361)
* Add option to generate current dep graph to saidump * Add log method entry
1 parent a4ee3ad commit 15ef685

File tree

1 file changed

+240
-1
lines changed

1 file changed

+240
-1
lines changed

saidump/saidump.cpp

+240-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#include <string>
2+
#include <set>
3+
#include <sstream>
24

35
extern "C" {
46
#include <sai.h>
@@ -16,6 +18,7 @@ struct CmdOptions
1618
{
1719
bool skipAttributes;
1820
bool dumpTempView;
21+
bool dumpGraph;
1922
};
2023

2124
CmdOptions g_cmdOptions;
@@ -39,13 +42,15 @@ CmdOptions handleCmdLine(int argc, char **argv)
3942
CmdOptions options;
4043

4144
options.dumpTempView = false;
45+
options.dumpGraph = false;
4246

43-
const char* const optstring = "th";
47+
const char* const optstring = "gth";
4448

4549
while(true)
4650
{
4751
static struct option long_options[] =
4852
{
53+
{ "dumpGraph", no_argument, 0, 'g' },
4954
{ "tempView", no_argument, 0, 't' },
5055
{ "help", no_argument, 0, 'h' },
5156
{ 0, 0, 0, 0 }
@@ -62,6 +67,11 @@ CmdOptions handleCmdLine(int argc, char **argv)
6267

6368
switch (c)
6469
{
70+
case 'g':
71+
SWSS_LOG_NOTICE("Dumping graph");
72+
options.dumpGraph = true;
73+
break;
74+
6575
case 't':
6676
SWSS_LOG_NOTICE("Dumping temp view");
6777
options.dumpTempView = true;
@@ -150,6 +160,226 @@ void print_attributes(size_t indent, const TableMap& map)
150160
}
151161
}
152162

163+
#define SAI_OBJECT_TYPE_PREFIX_LEN 16
164+
165+
void dumpGraph(const TableDump& td)
166+
{
167+
SWSS_LOG_ENTER();
168+
169+
std::map<sai_object_id_t, const sai_object_type_info_t*> oidtypemap;
170+
std::map<sai_object_type_t,const sai_object_type_info_t*> typemap;
171+
172+
std::cout << "digraph \"SAI Object Dependency Graph\" {" << std::endl;
173+
std::cout << "size=\"30,12\"; ratio = fill;" << std::endl;
174+
std::cout << "node [style=filled];" << std::endl;
175+
176+
// build object type map first
177+
178+
std::set<sai_object_type_t> definedtypes;
179+
180+
std::map<sai_object_type_t, int> usagemap;
181+
182+
for (const auto& key: td)
183+
{
184+
sai_object_meta_key_t meta_key;
185+
sai_deserialize_object_meta_key(key.first, meta_key);
186+
187+
auto info = sai_metadata_get_object_type_info(meta_key.objecttype);
188+
189+
typemap[info->objecttype] = info;
190+
191+
if (!info->isnonobjectid)
192+
oidtypemap[meta_key.objectkey.key.object_id] = info;
193+
194+
if (definedtypes.find(meta_key.objecttype) != definedtypes.end())
195+
continue;
196+
197+
definedtypes.insert(meta_key.objecttype);
198+
}
199+
200+
std::set<std::string> definedlinks;
201+
202+
std::set<sai_object_type_t> ref;
203+
std::set<sai_object_type_t> attrref;
204+
205+
for (const auto& key: td)
206+
{
207+
sai_object_meta_key_t meta_key;
208+
sai_deserialize_object_meta_key(key.first, meta_key);
209+
210+
auto info = sai_metadata_get_object_type_info(meta_key.objecttype);
211+
212+
// process non object id objects if any
213+
for (size_t j = 0; j < info->structmemberscount; ++j)
214+
{
215+
const sai_struct_member_info_t *m = info->structmembers[j];
216+
217+
if (m->membervaluetype == SAI_ATTR_VALUE_TYPE_OBJECT_ID)
218+
{
219+
sai_object_id_t member_oid = m->getoid(&meta_key);
220+
221+
auto member_info = oidtypemap.at(member_oid);
222+
223+
if (member_info->objecttype == SAI_OBJECT_TYPE_SWITCH)
224+
{
225+
// skip link of SWITCH to non object id object types, since
226+
// all of them contain switch_id
227+
continue;
228+
}
229+
230+
std::stringstream ss;
231+
232+
ss << std::string(member_info->objecttypename + SAI_OBJECT_TYPE_PREFIX_LEN) << " -> "
233+
<< std::string(info->objecttypename + SAI_OBJECT_TYPE_PREFIX_LEN)
234+
<< "[color=\"0.650 0.700 0.700\", style = dashed, penwidth=2]";
235+
236+
std::string link = ss.str();
237+
238+
if (definedlinks.find(link) != definedlinks.end())
239+
continue;
240+
241+
definedlinks.insert(link);
242+
243+
std::cout << link << std::endl;
244+
}
245+
}
246+
247+
// process attributes for this object
248+
249+
for (const auto&field: key.second)
250+
{
251+
const sai_attr_metadata_t *meta;
252+
sai_deserialize_attr_id(field.first, &meta);
253+
254+
if (!meta->isoidattribute || meta->isreadonly)
255+
{
256+
// skip non oid attributes and read only attributes
257+
continue;
258+
}
259+
260+
sai_attribute_t attr;
261+
262+
sai_deserialize_attr_value(field.second, *meta, attr, false);
263+
264+
sai_object_list_t list = {0, NULL};
265+
266+
switch (meta->attrvaluetype)
267+
{
268+
case SAI_ATTR_VALUE_TYPE_OBJECT_ID:
269+
list.count = 1;
270+
list.list = &attr.value.oid;
271+
break;
272+
273+
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_ID:
274+
if (attr.value.aclfield.enable)
275+
{
276+
list.count = 1;
277+
list.list = &attr.value.aclfield.data.oid;
278+
}
279+
break;
280+
281+
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_ID:
282+
if (attr.value.aclaction.enable)
283+
{
284+
list.count = 1;
285+
list.list = &attr.value.aclaction.parameter.oid;
286+
}
287+
break;
288+
289+
case SAI_ATTR_VALUE_TYPE_OBJECT_LIST:
290+
list = attr.value.objlist;
291+
break;
292+
293+
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_LIST:
294+
if (attr.value.aclfield.enable)
295+
list = attr.value.aclfield.data.objlist;
296+
break;
297+
298+
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_LIST:
299+
if (attr.value.aclaction.enable)
300+
list = attr.value.aclaction.parameter.objlist;
301+
break;
302+
303+
default:
304+
SWSS_LOG_THROW("attr value type: %d is not supported, FIXME", meta->attrvaluetype);
305+
}
306+
307+
for (uint32_t i = 0; i < list.count; ++i)
308+
{
309+
sai_object_id_t oid = list.list[i];
310+
311+
if (oid == SAI_NULL_OBJECT_ID)
312+
continue;
313+
314+
// this object type is not root, can be in the middle or leaf
315+
ref.insert(info->objecttype);
316+
317+
auto attr_oid_info = oidtypemap.at(oid);
318+
319+
std::stringstream ss;
320+
321+
attrref.insert(attr_oid_info->objecttype);
322+
323+
ss << std::string(attr_oid_info->objecttypename + SAI_OBJECT_TYPE_PREFIX_LEN) << " -> "
324+
<< std::string(info->objecttypename + SAI_OBJECT_TYPE_PREFIX_LEN)
325+
<< "[color=\"0.650 0.700 0.700\"]";
326+
327+
std::string link = ss.str();
328+
329+
if (definedlinks.find(link) != definedlinks.end())
330+
continue;
331+
332+
definedlinks.insert(link);
333+
334+
std::cout << link << std::endl;
335+
}
336+
337+
sai_deserialize_free_attribute_value(meta->attrvaluetype, attr);
338+
}
339+
}
340+
341+
for (auto t: typemap)
342+
{
343+
auto ot = t.first;
344+
auto info = t.second;
345+
346+
auto name = std::string(info->objecttypename + SAI_OBJECT_TYPE_PREFIX_LEN);
347+
348+
if (info->isnonobjectid)
349+
{
350+
std::cout << name << " [color=plum, shape = rect];\n";
351+
continue;
352+
}
353+
354+
if (ref.find(ot) != ref.end() && attrref.find(ot) != attrref.end())
355+
{
356+
std::cout << name << " [color=\"0.650 0.500 1.000\"];\n";
357+
continue;
358+
}
359+
360+
if (ref.find(ot) != ref.end() && attrref.find(ot) == attrref.end())
361+
{
362+
std::cout << name << " [color=\"0.355 0.563 1.000\", shape = rect];\n";
363+
continue;
364+
}
365+
366+
if (ref.find(ot) == ref.end() && attrref.find(ot) != attrref.end())
367+
{
368+
std::cout << name << " [color=\"0.650 0.200 1.000\"];\n";
369+
continue;
370+
}
371+
372+
/* objects which are there but not referenced nowhere for example STP */
373+
374+
std::cout << name << " [color=\"0.650 0.200 1.000\" shape=rect];\n";
375+
}
376+
377+
std::cout << "SWITCH -> PORT[dir=\"none\", color=\"red\", peripheries = 2, penwidth=2.0 , style = dashed ];" <<std::endl;
378+
std::cout << "SWITCH [color=orange, shape = parallelogram, peripheries = 2];" <<std::endl;
379+
std::cout << "PORT [color=gold, shape = diamond, peripheries=2];" << std::endl;
380+
std::cout << "}" << std::endl;
381+
}
382+
153383
int main(int argc, char ** argv)
154384
{
155385
swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_DEBUG);
@@ -199,6 +429,13 @@ int main(int argc, char ** argv)
199429
}
200430
}
201431

432+
if (g_cmdOptions.dumpGraph)
433+
{
434+
dumpGraph(dump);
435+
436+
return EXIT_SUCCESS;
437+
}
438+
202439
for (const auto&key: dump)
203440
{
204441
auto start = key.first.find_first_of(":");
@@ -213,4 +450,6 @@ int main(int argc, char ** argv)
213450

214451
std::cout << std::endl;
215452
}
453+
454+
return EXIT_SUCCESS;
216455
}

0 commit comments

Comments
 (0)