in saidump/SaiDump.cpp [184:410]
void SaiDump::dumpGraphFun(const TableDump& td)
{
SWSS_LOG_ENTER();
std::map<sai_object_id_t, const sai_object_type_info_t*> oidtypemap;
std::map<sai_object_type_t,const sai_object_type_info_t*> typemap;
std::cout << "digraph \"SAI Object Dependency Graph\" {" << std::endl;
std::cout << "size = \"30,12\"; ratio = fill;" << std::endl;
std::cout << "node [ style = filled ];" << std::endl;
// build object type map first
std::set<sai_object_type_t> definedtypes;
std::map<sai_object_type_t, int> usagemap;
for (const auto& key: td)
{
sai_object_meta_key_t meta_key;
sai_deserialize_object_meta_key(key.first, meta_key);
auto info = sai_metadata_get_object_type_info(meta_key.objecttype);
typemap[info->objecttype] = info;
if (!info->isnonobjectid)
oidtypemap[meta_key.objectkey.key.object_id] = info;
if (definedtypes.find(meta_key.objecttype) != definedtypes.end())
continue;
definedtypes.insert(meta_key.objecttype);
}
std::set<std::string> definedlinks;
std::set<sai_object_type_t> ref;
std::set<sai_object_type_t> attrref;
#define SAI_OBJECT_TYPE_PREFIX_LEN (sizeof("SAI_OBJECT_TYPE_") - 1)
for (const auto& key: td)
{
sai_object_meta_key_t meta_key;
sai_deserialize_object_meta_key(key.first, meta_key);
auto info = sai_metadata_get_object_type_info(meta_key.objecttype);
// process non object id objects if any
for (size_t j = 0; j < info->structmemberscount; ++j)
{
const sai_struct_member_info_t *m = info->structmembers[j];
if (m->membervaluetype == SAI_ATTR_VALUE_TYPE_OBJECT_ID)
{
sai_object_id_t member_oid = m->getoid(&meta_key);
auto member_info = oidtypemap.at(member_oid);
if (member_info->objecttype == SAI_OBJECT_TYPE_SWITCH)
{
// skip link of SWITCH to non object id object types, since
// all of them contain switch_id
continue;
}
std::stringstream ss;
ss << std::string(member_info->objecttypename + SAI_OBJECT_TYPE_PREFIX_LEN) << " -> "
<< std::string(info->objecttypename + SAI_OBJECT_TYPE_PREFIX_LEN)
<< "[ color=\"" << GV_ARROW_COLOR << "\", style = dashed, penwidth = 2 ]";
std::string link = ss.str();
if (definedlinks.find(link) != definedlinks.end())
continue;
definedlinks.insert(link);
std::cout << link << std::endl;
}
}
// process attributes for this object
for (const auto&field: key.second)
{
const sai_attr_metadata_t *meta;
sai_deserialize_attr_id(field.first, &meta);
if (!meta->isoidattribute || meta->isreadonly)
{
// skip non oid attributes and read only attributes
continue;
}
sai_attribute_t attr;
sai_deserialize_attr_value(field.second, *meta, attr, false);
sai_object_list_t list = { 0, NULL };
switch (meta->attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_OBJECT_ID:
list.count = 1;
list.list = &attr.value.oid;
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_ID:
if (attr.value.aclfield.enable)
{
list.count = 1;
list.list = &attr.value.aclfield.data.oid;
}
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_ID:
if (attr.value.aclaction.enable)
{
list.count = 1;
list.list = &attr.value.aclaction.parameter.oid;
}
break;
case SAI_ATTR_VALUE_TYPE_OBJECT_LIST:
list = attr.value.objlist;
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_LIST:
if (attr.value.aclfield.enable)
list = attr.value.aclfield.data.objlist;
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_LIST:
if (attr.value.aclaction.enable)
list = attr.value.aclaction.parameter.objlist;
break;
default:
SWSS_LOG_THROW("attr value type: %d is not supported, FIXME", meta->attrvaluetype);
}
for (uint32_t i = 0; i < list.count; ++i)
{
sai_object_id_t oid = list.list[i];
if (oid == SAI_NULL_OBJECT_ID)
continue;
// this object type is not root, can be in the middle or leaf
ref.insert(info->objecttype);
auto attr_oid_info = oidtypemap.at(oid);
std::stringstream ss;
attrref.insert(attr_oid_info->objecttype);
ss << std::string(attr_oid_info->objecttypename + SAI_OBJECT_TYPE_PREFIX_LEN) << " -> "
<< std::string(info->objecttypename + SAI_OBJECT_TYPE_PREFIX_LEN)
<< "[ color = \"" << GV_ARROW_COLOR << "\" ]";
std::string link = ss.str();
if (definedlinks.find(link) != definedlinks.end())
continue;
definedlinks.insert(link);
std::cout << link << std::endl;
}
sai_deserialize_free_attribute_value(meta->attrvaluetype, attr);
}
}
for (auto t: typemap)
{
auto ot = t.first;
auto info = t.second;
auto name = std::string(info->objecttypename + SAI_OBJECT_TYPE_PREFIX_LEN);
if (info->isnonobjectid)
{
/* non object id leafs */
std::cout << name << " [ color = plum, shape = rect ];\n";
continue;
}
if (ref.find(ot) != ref.end() && attrref.find(ot) != attrref.end())
{
/* middle nodes */
std::cout << name << " [ color =\"" << GV_NODE_COLOR << "\" ];\n";
continue;
}
if (ref.find(ot) != ref.end() && attrref.find(ot) == attrref.end())
{
/* leafs */
std::cout << name << " [ color = palegreen, shape = rect ];\n";
continue;
}
if (ref.find(ot) == ref.end() && attrref.find(ot) != attrref.end())
{
/* roots */
std::cout << name << " [ color = \"" << GV_ROOT_COLOR << "\" ];\n";
continue;
}
/* objects which are there but not referenced nowhere for example STP */
std::cout << name << " [ color = \"" << GV_ROOT_COLOR << "\", shape = rect ];\n";
}
std::cout << "SWITCH -> PORT [ dir = none, color = red, peripheries = 2, penwidth = 2, style = dashed ];" << std::endl;
std::cout << "SWITCH [ color = orange, fillcolor = orange, shape = parallelogram, peripheries = 2 ];" << std::endl;
std::cout << "PORT [ color = gold, shape = diamond, peripheries = 2 ];" << std::endl;
std::cout << "}" << std::endl;
}