1
1
#include < string>
2
+ #include < set>
3
+ #include < sstream>
2
4
3
5
extern " C" {
4
6
#include < sai.h>
@@ -16,6 +18,7 @@ struct CmdOptions
16
18
{
17
19
bool skipAttributes;
18
20
bool dumpTempView;
21
+ bool dumpGraph;
19
22
};
20
23
21
24
CmdOptions g_cmdOptions;
@@ -39,13 +42,15 @@ CmdOptions handleCmdLine(int argc, char **argv)
39
42
CmdOptions options;
40
43
41
44
options.dumpTempView = false ;
45
+ options.dumpGraph = false ;
42
46
43
- const char * const optstring = " th " ;
47
+ const char * const optstring = " gth " ;
44
48
45
49
while (true )
46
50
{
47
51
static struct option long_options[] =
48
52
{
53
+ { " dumpGraph" , no_argument, 0 , ' g' },
49
54
{ " tempView" , no_argument, 0 , ' t' },
50
55
{ " help" , no_argument, 0 , ' h' },
51
56
{ 0 , 0 , 0 , 0 }
@@ -62,6 +67,11 @@ CmdOptions handleCmdLine(int argc, char **argv)
62
67
63
68
switch (c)
64
69
{
70
+ case ' g' :
71
+ SWSS_LOG_NOTICE (" Dumping graph" );
72
+ options.dumpGraph = true ;
73
+ break ;
74
+
65
75
case ' t' :
66
76
SWSS_LOG_NOTICE (" Dumping temp view" );
67
77
options.dumpTempView = true ;
@@ -150,6 +160,226 @@ void print_attributes(size_t indent, const TableMap& map)
150
160
}
151
161
}
152
162
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
+
153
383
int main (int argc, char ** argv)
154
384
{
155
385
swss::Logger::getInstance ().setMinPrio (swss::Logger::SWSS_DEBUG);
@@ -199,6 +429,13 @@ int main(int argc, char ** argv)
199
429
}
200
430
}
201
431
432
+ if (g_cmdOptions.dumpGraph )
433
+ {
434
+ dumpGraph (dump);
435
+
436
+ return EXIT_SUCCESS;
437
+ }
438
+
202
439
for (const auto &key: dump)
203
440
{
204
441
auto start = key.first .find_first_of (" :" );
@@ -213,4 +450,6 @@ int main(int argc, char ** argv)
213
450
214
451
std::cout << std::endl;
215
452
}
453
+
454
+ return EXIT_SUCCESS;
216
455
}
0 commit comments