meta/saidepgraphgen.cpp (181 lines of code) (raw):

/** * Copyright (c) 2014 Microsoft Open Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT * LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS * FOR A PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT. * * See the Apache Version 2.0 License for specific language governing * permissions and limitations under the License. * * Microsoft would like to thank the following companies for their review and * assistance with these files: Intel Corporation, Mellanox Technologies Ltd, * Dell Products, L.P., Facebook, Inc., Marvell International Ltd. * * @file saidepgraphgen.cpp * * @brief This module defines SAI Dependency Graph Generator */ #include <iostream> #include <map> #include <set> #include <stdlib.h> #include <string.h> extern "C" { #include "saimetadata.h" } // node name #define NN(x) (sai_metadata_get_enum_value_short_name(&sai_metadata_enum_sai_object_type_t,(x))) static std::set<sai_object_type_t> source; static std::set<sai_object_type_t> target; static bool show_switch_links = false; static bool show_read_only_links = false; static bool show_extensions = false; static void process_object_type_attributes( _In_ const sai_attr_metadata_t* const* const meta_attr_list, _In_ sai_object_type_t current_object_type) { std::set<sai_object_type_t> otset; std::set<sai_object_type_t> rotset; for (int i = 0; meta_attr_list[i] != NULL; ++i) { const sai_attr_metadata_t* meta = meta_attr_list[i]; if (meta->allowedobjecttypeslength == 0) { // skip attributes that don't contain object id's continue; } bool ro = SAI_HAS_FLAG_READ_ONLY(meta->flags); if (ro && !show_read_only_links) { // skip attributes that are read only continue; } std::string style; switch (meta->attrvaluetype) { case SAI_ATTR_VALUE_TYPE_OBJECT_LIST: case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_LIST: case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_LIST: // we can miss some objects if same object can be set // as list in one attribute and as single object in // another attribute style = "style=bold"; break; default: break; } // this attribute supports objects if (meta->allowedobjecttypeslength > 1) { // point arrows to the same point origin when this is single attribute style += " samehead=" + std::string(meta->attridname); } for (uint32_t j = 0; j < meta->allowedobjecttypeslength; j++) { sai_object_type_t ot = meta->allowedobjecttypes[j]; if (otset.find(ot) != otset.end()) { // node was already defined continue; } const char* current = NN(current_object_type); const char* dep = NN(ot); if (ro) { if (rotset.find(ot) != rotset.end()) { continue; } rotset.insert(ot); std::cout << dep << " -> " << current << " [ " << style << " color=\"red\" ];\n"; continue; } std::cout << dep << " -> " << current << " [ " << style << " color=\"0.650 0.700 0.700\"];\n"; otset.insert(ot); source.insert(ot); target.insert(current_object_type); } } } static void process_object_types() { for (int idx = 1; sai_metadata_all_object_type_infos[idx]; ++idx) { const sai_attr_metadata_t* const* const meta = sai_metadata_all_object_type_infos[idx]->attrmetadata; process_object_type_attributes(meta, sai_metadata_all_object_type_infos[idx]->objecttype); } } static void process_colors() { for (int idx = 1; sai_metadata_all_object_type_infos[idx]; ++idx) { sai_object_type_t ot = sai_metadata_all_object_type_infos[idx]->objecttype; bool is_source = source.find(ot) != source.end(); bool is_target = target.find(ot) != target.end(); if (is_source && is_target) { // node is target and source, so it's in the middle std::cout << NN(ot) << " [color=\"0.650 0.500 1.000\"];\n"; } else if (is_target) { // this node is a leaf std::cout << NN(ot) << " [color=\"0.355 0.563 1.000\", shape = rect];\n"; } else if (is_source) { std::cout << NN(ot) << " [color=\"0.650 0.200 1.000\"];\n"; } else { if (ot == SAI_OBJECT_TYPE_NULL) { continue; } std::cout << NN(ot) << " [color=coral, shape = note];\n"; } } for (size_t idx = 1 ; sai_metadata_all_object_type_infos[idx]; ++idx) { const sai_object_type_info_t* oi = sai_metadata_all_object_type_infos[idx]; if (!oi->isnonobjectid) { continue; } if (oi->objecttype >= SAI_OBJECT_TYPE_MAX && !show_extensions) { continue; } std::cout << NN(oi->objecttype) << " [color=plum, shape = rect];\n"; } } #define PRINT_NN(x,y,c)\ std::cout << NN(SAI_OBJECT_TYPE_ ## x) << " -> " << NN(SAI_OBJECT_TYPE_ ## y) << c; static void process_nonobjectid_connections() { const char* c = " [color=\"0.650 0.700 0.700\", style = dashed, penwidth=2];\n"; for (size_t idx = 1 ; sai_metadata_all_object_type_infos[idx]; ++idx) { const sai_object_type_info_t* oi = sai_metadata_all_object_type_infos[idx]; if (!oi->isnonobjectid) { continue; } if (oi->objecttype >= SAI_OBJECT_TYPE_MAX && !show_extensions) { continue; } for (size_t j = 0; j < oi->structmemberscount; ++j) { const sai_struct_member_info_t* sm = oi->structmembers[j]; if (sm->membervaluetype == SAI_ATTR_VALUE_TYPE_OBJECT_ID) { for (size_t k = 0; k < sm->allowedobjecttypeslength; ++k) { sai_object_type_t ot = sm->allowedobjecttypes[k]; if (ot == SAI_OBJECT_TYPE_SWITCH && !show_switch_links) { // skip switch dependency since switch // is used everywhere and will pollute graph continue; } std::cout << NN(ot) << " -> " << NN(oi->objecttype) << c; } } else if (sm->isvlan) { std::cout << NN(SAI_OBJECT_TYPE_VLAN) << " -> " << NN(oi->objecttype) << c; } } } PRINT_NN(SWITCH, PORT, "[dir=\"none\", color=\"red\", peripheries = 2, penwidth=2.0 , style = dashed ];\n"); } int main(int argc, char** argv) { for (int i = 1; i < argc; ++i) { show_switch_links |= strcmp(argv[i], "-s") == 0; show_read_only_links |= strcmp(argv[i], "-r") == 0; show_extensions |= strcmp(argv[i], "-e") == 0; } std::cout << "digraph \"SAI Object Dependency Graph\" {\n"; std::cout << "size=\"30,12\"; ratio = fill;\n"; std::cout << "node [style=filled];\n"; process_object_types(); process_nonobjectid_connections(); process_colors(); std::cout << NN(SAI_OBJECT_TYPE_SWITCH) << " [color=orange, shape = parallelogram, peripheries = 2];\n"; std::cout << NN(SAI_OBJECT_TYPE_PORT) << " [color=gold, shape = diamond, peripheries=2];\n"; std::cout << "}\n"; return 0; }