Page MenuHomeFreeBSD

usr.sbin/ngctl: Generate more compact GraphWiz output
Needs ReviewPublic

Authored by lutz_donnerhacke.de on Oct 10 2019, 12:21 PM.

Details

Reviewers
vmaffione
linimon
Group Reviewers
network
Summary

The output of "ngctl dot" is suitable for small netgraph networks. Even moderate complex netgraph setups (about a dozen nodes) are hard to understand from the .dot output, because each node and each hook are shown as a full blown structure.

This patch allows to generate much more compact output and graphs by omitting the extra structures for the individual hooks. Instead the names of the hooks are labels to the edges.

Test Plan

Generate a moderatly complex netgraph.

$ ngctl dot
graph netgraph {
	edge [ weight = 1.0 ];
	node [ shape = record, fontsize = 12 ] {
		"2" [ label = "{hsi1:|{eiface|[2]:}}" ];
		"3" [ label = "{cpe1:|{vlan|[3]:}}" ];
		"4" [ label = "{bng2:|{vlan|[4]:}}" ];
		"5" [ label = "{\<unnamed\>:|{vlan|[5]:}}" ];
		"6" [ label = "{xc:|{tee|[6]:}}" ];
		"7" [ label = "{\<unnamed\>:|{vlan|[7]:}}" ];
		"8" [ label = "{rotate:|{vlan_rotate|[8]:}}" ];
		"9" [ label = "{\<unnamed\>:|{vlan|[9]:}}" ];
		"a" [ label = "{ngeth1:|{eiface|[a]:}}" ];
		"b" [ label = "{tester:|{source|[b]:}}" ];
		"f" [ label = "{\<unnamed\>:|{bridge|[f]:}}" ];
		"10" [ label = "{\<unnamed\>:|{bridge|[10]:}}" ];
		"11" [ label = "{ngeth2:|{eiface|[11]:}}" ];
		"12" [ label = "{ngeth3:|{eiface|[12]:}}" ];
	};
	node [ shape = octagon, fontsize = 10 ] {
		"2.ether" [ label = "ether" ];
	};
	{
		edge [ weight = 2.0, style = bold ];
		"2" -- "2.ether";
	};
	node [ shape = octagon, fontsize = 10 ] {
		"3.downstream" [ label = "downstream" ];
		"3.hsi" [ label = "hsi" ];
	};
	{
		edge [ weight = 2.0, style = bold ];
		"3" -- "3.downstream";
		"3" -- "3.hsi";
	};
	"3.hsi" -- "2.ether";
	node [ shape = octagon, fontsize = 10 ] {
		"4.downstream" [ label = "downstream" ];
		"4.line1" [ label = "line1" ];
	};
	{
		edge [ weight = 2.0, style = bold ];
		"4" -- "4.downstream";
		"4" -- "4.line1";
	};
	"4.line1" -- "3.downstream";
	node [ shape = octagon, fontsize = 10 ] {
		"5.downstream" [ label = "downstream" ];
		"5.xc1" [ label = "xc1" ];
	};
	{
		edge [ weight = 2.0, style = bold ];
		"5" -- "5.downstream";
		"5" -- "5.xc1";
	};
	"5.xc1" -- "4.downstream";
	node [ shape = octagon, fontsize = 10 ] {
		"6.right2left" [ label = "right2left" ];
		"6.left2right" [ label = "left2right" ];
		"6.right" [ label = "right" ];
		"6.left" [ label = "left" ];
	};
	{
		edge [ weight = 2.0, style = bold ];
		"6" -- "6.right2left";
		"6" -- "6.left2right";
		"6" -- "6.right";
		"6" -- "6.left";
	};
	"6.left" -- "5.downstream";
	node [ shape = octagon, fontsize = 10 ] {
		"7.bng2" [ label = "bng2" ];
		"7.downstream" [ label = "downstream" ];
	};
	{
		edge [ weight = 2.0, style = bold ];
		"7" -- "7.bng2";
		"7" -- "7.downstream";
	};
	"7.downstream" -- "6.right";
	node [ shape = octagon, fontsize = 10 ] {
		"8.ordered" [ label = "ordered" ];
		"8.original" [ label = "original" ];
	};
	{
		edge [ weight = 2.0, style = bold ];
		"8" -- "8.ordered";
		"8" -- "8.original";
	};
	"8.original" -- "7.bng2";
	node [ shape = octagon, fontsize = 10 ] {
		"9.hsi" [ label = "hsi" ];
		"9.downstream" [ label = "downstream" ];
	};
	{
		edge [ weight = 2.0, style = bold ];
		"9" -- "9.hsi";
		"9" -- "9.downstream";
	};
	"9.downstream" -- "8.ordered";
	node [ shape = octagon, fontsize = 10 ] {
		"a.ether" [ label = "ether" ];
	};
	{
		edge [ weight = 2.0, style = bold ];
		"a" -- "a.ether";
	};
	"a.ether" -- "9.hsi";
	node [ shape = octagon, fontsize = 10 ] {
		"b.output" [ label = "output" ];
		"b.input" [ label = "input" ];
	};
	{
		edge [ weight = 2.0, style = bold ];
		"b" -- "b.output";
		"b" -- "b.input";
	};
	"b.output" -- "6.right2left";
	"b.input" -- "6.left2right";
	node [ shape = octagon, fontsize = 10 ] {
		"f.link2" [ label = "link2" ];
		"f.link1" [ label = "link1" ];
		"f.link123" [ label = "link123" ];
	};
	{
		edge [ weight = 2.0, style = bold ];
		"f" -- "f.link2";
		"f" -- "f.link1";
		"f" -- "f.link123";
	};
	node [ shape = octagon, fontsize = 10 ] {
		"10.link2" [ label = "link2" ];
		"10.link1" [ label = "link1" ];
		"10.link123" [ label = "link123" ];
	};
	{
		edge [ weight = 2.0, style = bold ];
		"10" -- "10.link2";
		"10" -- "10.link1";
		"10" -- "10.link123";
	};
	"10.link2" -- "f.link2";
	"10.link1" -- "f.link1";
	node [ shape = octagon, fontsize = 10 ] {
		"11.ether" [ label = "ether" ];
	};
	{
		edge [ weight = 2.0, style = bold ];
		"11" -- "11.ether";
	};
	"11.ether" -- "f.link123";
	node [ shape = octagon, fontsize = 10 ] {
		"12.ether" [ label = "ether" ];
	};
	{
		edge [ weight = 2.0, style = bold ];
		"12" -- "12.ether";
	};
	"12.ether" -- "10.link123";
}

And now the compact output:

$ ngctl dot -c
digraph netgraph {
	edge [ dir = "none", fontsize = 10 ];
	node [ shape = record, fontsize = 12 ] {
		"2" [ label = "{hsi1:|{eiface|[2]:}}" ];
		"3" [ label = "{cpe1:|{vlan|[3]:}}" ];
		"4" [ label = "{bng2:|{vlan|[4]:}}" ];
		"5" [ label = "{\<unnamed\>:|{vlan|[5]:}}" ];
		"6" [ label = "{xc:|{tee|[6]:}}" ];
		"7" [ label = "{\<unnamed\>:|{vlan|[7]:}}" ];
		"8" [ label = "{rotate:|{vlan_rotate|[8]:}}" ];
		"9" [ label = "{\<unnamed\>:|{vlan|[9]:}}" ];
		"a" [ label = "{ngeth1:|{eiface|[a]:}}" ];
		"b" [ label = "{tester:|{source|[b]:}}" ];
		"f" [ label = "{\<unnamed\>:|{bridge|[f]:}}" ];
		"10" [ label = "{\<unnamed\>:|{bridge|[10]:}}" ];
		"11" [ label = "{ngeth2:|{eiface|[11]:}}" ];
		"12" [ label = "{ngeth3:|{eiface|[12]:}}" ];
	};
	"2" -> "3" [ headlabel = "hsi", taillabel ="ether" ] ;
	"3" -> "4" [ headlabel = "line1", taillabel ="downstream" ] ;
	"4" -> "5" [ headlabel = "xc1", taillabel ="downstream" ] ;
	"5" -> "6" [ headlabel = "left", taillabel ="downstream" ] ;
	"6" -> "7" [ headlabel = "downstream", taillabel ="right" ] ;
	"7" -> "8" [ headlabel = "original", taillabel ="bng2" ] ;
	"8" -> "9" [ headlabel = "downstream", taillabel ="ordered" ] ;
	"9" -> "a" [ headlabel = "ether", taillabel ="hsi" ] ;
	"6" -> "b" [ headlabel = "output", taillabel ="right2left" ] ;
	"6" -> "b" [ headlabel = "input", taillabel ="left2right" ] ;
	"f" -> "10" [ headlabel = "link2", taillabel ="link2" ] ;
	"f" -> "10" [ headlabel = "link1", taillabel ="link1" ] ;
	"f" -> "11" [ headlabel = "ether", taillabel ="link123" ] ;
	"10" -> "12" [ headlabel = "ether", taillabel ="link123" ] ;
}

Help text ist also available:

$ ngctl help dot
 usage:    dot [-c] [outputfile]
 Aliases:  graphviz, confdot
 Summary:  Produce a GraphViz (.dot) of the entire netgraph.
 Description:
  If no outputfile is specified, stdout will be assumed. The 
  optional -c argument generates a graph without separate 
  structures for egde names. Such a graph is more compact.

You may display such graphs using http://www.webgraphviz.com/

Diff Detail

Repository
rS FreeBSD src repository
Lint
No Linters Available
Unit
No Unit Test Coverage
Build Status
Buildable 30039
Build 27850: arc lint + arc unit

Event Timeline

linimon resigned from this revision.Oct 13 2019, 6:45 AM

I'm afraid I don't know anything about this code.

Change location of working directory locally at my machine.

I tested this patch in our test lab with a lot of netgraph nodes. And I find it very useful.

usr.sbin/ngctl/dot.c
119–126

if<space>(

174–189

Ditto

195–207

Ditto

Fixed spacing for "if (" statements.
Running the whole source through indent(1) would make a much larger patch.