xref: /freebsd/usr.sbin/ngctl/dot.c (revision 9fe5fadaf1156dc9f0372c8a8a2623bc202aeb5c)
1bbd6d60aSBrian Feldman 
2bbd6d60aSBrian Feldman /*
3bbd6d60aSBrian Feldman  * dot.c
4bbd6d60aSBrian Feldman  *
5bbd6d60aSBrian Feldman  * Copyright (c) 2004 Brian Fundakowski Feldman
6bbd6d60aSBrian Feldman  * Copyright (c) 1996-1999 Whistle Communications, Inc.
7bbd6d60aSBrian Feldman  * All rights reserved.
8bbd6d60aSBrian Feldman  *
9bbd6d60aSBrian Feldman  * Subject to the following obligations and disclaimer of warranty, use and
10bbd6d60aSBrian Feldman  * redistribution of this software, in source or object code forms, with or
11bbd6d60aSBrian Feldman  * without modifications are expressly permitted by Whistle Communications;
12bbd6d60aSBrian Feldman  * provided, however, that:
13bbd6d60aSBrian Feldman  * 1. Any and all reproductions of the source or object code must include the
14bbd6d60aSBrian Feldman  *    copyright notice above and the following disclaimer of warranties; and
15bbd6d60aSBrian Feldman  * 2. No rights are granted, in any manner or form, to use Whistle
16bbd6d60aSBrian Feldman  *    Communications, Inc. trademarks, including the mark "WHISTLE
17bbd6d60aSBrian Feldman  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18bbd6d60aSBrian Feldman  *    such appears in the above copyright notice or in the software.
19bbd6d60aSBrian Feldman  *
20bbd6d60aSBrian Feldman  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21bbd6d60aSBrian Feldman  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22bbd6d60aSBrian Feldman  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23bbd6d60aSBrian Feldman  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24bbd6d60aSBrian Feldman  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25bbd6d60aSBrian Feldman  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26bbd6d60aSBrian Feldman  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27bbd6d60aSBrian Feldman  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28bbd6d60aSBrian Feldman  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29bbd6d60aSBrian Feldman  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30bbd6d60aSBrian Feldman  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31bbd6d60aSBrian Feldman  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32bbd6d60aSBrian Feldman  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33bbd6d60aSBrian Feldman  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34bbd6d60aSBrian Feldman  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35bbd6d60aSBrian Feldman  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36bbd6d60aSBrian Feldman  * OF SUCH DAMAGE.
37bbd6d60aSBrian Feldman  *
38bbd6d60aSBrian Feldman  * $FreeBSD$
39bbd6d60aSBrian Feldman  */
40bbd6d60aSBrian Feldman 
41bbd6d60aSBrian Feldman #include <inttypes.h>
42bbd6d60aSBrian Feldman 
43bbd6d60aSBrian Feldman #include "ngctl.h"
44bbd6d60aSBrian Feldman 
45bbd6d60aSBrian Feldman #define UNNAMED		"\\<unnamed\\>"
46bbd6d60aSBrian Feldman 
47bbd6d60aSBrian Feldman static int DotCmd(int ac, char **av);
48bbd6d60aSBrian Feldman 
49bbd6d60aSBrian Feldman const struct ngcmd dot_cmd = {
50bbd6d60aSBrian Feldman 	DotCmd,
51bbd6d60aSBrian Feldman 	"dot [outputfile]",
52bbd6d60aSBrian Feldman 	"Produce a GraphViz (.dot) of the entire netgraph.",
53bbd6d60aSBrian Feldman 	"If no outputfile is specified, stdout will be assumed.",
54bbd6d60aSBrian Feldman 	{ "graphviz", "confdot" }
55bbd6d60aSBrian Feldman };
56bbd6d60aSBrian Feldman 
57bbd6d60aSBrian Feldman static int
58bbd6d60aSBrian Feldman DotCmd(int ac, char **av)
59bbd6d60aSBrian Feldman {
609fe5fadaSRuslan Ermilov 	struct ng_mesg *nlresp;
619fe5fadaSRuslan Ermilov 	struct namelist *nlist;
62bbd6d60aSBrian Feldman 	FILE *f = stdout;
63723c1c2eSRuslan Ermilov 	int ch;
64723c1c2eSRuslan Ermilov 	u_int i;
65bbd6d60aSBrian Feldman 
66bbd6d60aSBrian Feldman 	/* Get options */
67bbd6d60aSBrian Feldman 	optind = 1;
68bbd6d60aSBrian Feldman 	while ((ch = getopt(ac, av, "")) != EOF) {
69bbd6d60aSBrian Feldman 		switch (ch) {
70bbd6d60aSBrian Feldman 		case '?':
71bbd6d60aSBrian Feldman 		default:
72bbd6d60aSBrian Feldman 			return (CMDRTN_USAGE);
73bbd6d60aSBrian Feldman 			break;
74bbd6d60aSBrian Feldman 		}
75bbd6d60aSBrian Feldman 	}
76bbd6d60aSBrian Feldman 	ac -= optind;
77bbd6d60aSBrian Feldman 	av += optind;
78bbd6d60aSBrian Feldman 
79bbd6d60aSBrian Feldman 	/* Get arguments */
80bbd6d60aSBrian Feldman 	switch (ac) {
81bbd6d60aSBrian Feldman 	case 1:
82bbd6d60aSBrian Feldman 		f = fopen(av[0], "w");
83bbd6d60aSBrian Feldman 		if (f == NULL) {
84bbd6d60aSBrian Feldman 			warn("Could not open %s for writing", av[0]);
85bbd6d60aSBrian Feldman 			return (CMDRTN_ERROR);
86bbd6d60aSBrian Feldman 		}
87bbd6d60aSBrian Feldman 	case 0:
88bbd6d60aSBrian Feldman 		break;
89bbd6d60aSBrian Feldman 	default:
90bbd6d60aSBrian Feldman 		if (f != stdout)
91bbd6d60aSBrian Feldman 			(void)fclose(f);
92bbd6d60aSBrian Feldman 		return (CMDRTN_USAGE);
93bbd6d60aSBrian Feldman 	}
94bbd6d60aSBrian Feldman 
95bbd6d60aSBrian Feldman 	/* Get list of nodes */
96bbd6d60aSBrian Feldman 	if (NgSendMsg(csock, ".", NGM_GENERIC_COOKIE, NGM_LISTNODES, NULL,
97bbd6d60aSBrian Feldman 	    0) < 0) {
98bbd6d60aSBrian Feldman 		warn("send listnodes msg");
99bbd6d60aSBrian Feldman 		goto error;
100bbd6d60aSBrian Feldman 	}
1019fe5fadaSRuslan Ermilov 	if (NgAllocRecvMsg(csock, &nlresp, NULL) < 0) {
102bbd6d60aSBrian Feldman 		warn("recv listnodes msg");
103bbd6d60aSBrian Feldman 		goto error;
104bbd6d60aSBrian Feldman 	}
105bbd6d60aSBrian Feldman 
1069fe5fadaSRuslan Ermilov 	nlist = (struct namelist *)nlresp->data;
107bbd6d60aSBrian Feldman 	fprintf(f, "graph netgraph {\n");
108bbd6d60aSBrian Feldman 	/* TODO: implement rank = same or subgraphs at some point */
109bbd6d60aSBrian Feldman 	fprintf(f, "\tedge [ weight = 1.0 ];\n");
110bbd6d60aSBrian Feldman 	fprintf(f, "\tnode [ shape = record, fontsize = 12 ] {\n");
111bbd6d60aSBrian Feldman 	for (i = 0; i < nlist->numnames; i++)
112bbd6d60aSBrian Feldman 		fprintf(f, "\t\t\"%jx\" [ label = \"{%s:|{%s|[%jx]:}}\" ];\n",
113bbd6d60aSBrian Feldman 		    (uintmax_t)nlist->nodeinfo[i].id,
114bbd6d60aSBrian Feldman 		    nlist->nodeinfo[i].name[0] != '\0' ?
115bbd6d60aSBrian Feldman 		    nlist->nodeinfo[i].name : UNNAMED,
116bbd6d60aSBrian Feldman 		    nlist->nodeinfo[i].type, (uintmax_t)nlist->nodeinfo[i].id);
117bbd6d60aSBrian Feldman 	fprintf(f, "\t};\n");
118bbd6d60aSBrian Feldman 
119bbd6d60aSBrian Feldman 	fprintf(f, "\tsubgraph cluster_disconnected {\n");
120bbd6d60aSBrian Feldman 	fprintf(f, "\t\tbgcolor = pink;\n");
121bbd6d60aSBrian Feldman 	for (i = 0; i < nlist->numnames; i++)
122bbd6d60aSBrian Feldman 		if (nlist->nodeinfo[i].hooks == 0)
123bbd6d60aSBrian Feldman 			fprintf(f, "\t\t\"%jx\";\n",
124bbd6d60aSBrian Feldman 			    (uintmax_t)nlist->nodeinfo[i].id);
125bbd6d60aSBrian Feldman 	fprintf(f, "\t};\n");
126bbd6d60aSBrian Feldman 
127bbd6d60aSBrian Feldman 	for (i = 0; i < nlist->numnames; i++) {
1289fe5fadaSRuslan Ermilov 		struct ng_mesg *hlresp;
1299fe5fadaSRuslan Ermilov 		struct hooklist *hlist;
1309fe5fadaSRuslan Ermilov 		struct nodeinfo *ninfo;
131bbd6d60aSBrian Feldman 		char path[NG_PATHSIZ];
132723c1c2eSRuslan Ermilov 		u_int j;
133bbd6d60aSBrian Feldman 
134bbd6d60aSBrian Feldman 		(void)snprintf(path, sizeof(path), "[%jx]:",
135bbd6d60aSBrian Feldman 		    (uintmax_t)nlist->nodeinfo[i].id);
136bbd6d60aSBrian Feldman 
137bbd6d60aSBrian Feldman 		/* Get node info and hook list */
138bbd6d60aSBrian Feldman 		if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
139bbd6d60aSBrian Feldman 		    NULL, 0) < 0) {
1409fe5fadaSRuslan Ermilov 			free(nlresp);
141bbd6d60aSBrian Feldman 			warn("send listhooks msg");
142bbd6d60aSBrian Feldman 			goto error;
143bbd6d60aSBrian Feldman 		}
1449fe5fadaSRuslan Ermilov 		if (NgAllocRecvMsg(csock, &hlresp, NULL) < 0) {
1459fe5fadaSRuslan Ermilov 			free(nlresp);
146bbd6d60aSBrian Feldman 			warn("recv listhooks msg");
147bbd6d60aSBrian Feldman 			goto error;
148bbd6d60aSBrian Feldman 		}
149bbd6d60aSBrian Feldman 
1509fe5fadaSRuslan Ermilov 		hlist = (struct hooklist *)hlresp->data;
1519fe5fadaSRuslan Ermilov 		ninfo = &hlist->nodeinfo;
1529fe5fadaSRuslan Ermilov 		if (ninfo->hooks == 0) {
1539fe5fadaSRuslan Ermilov 			free(hlresp);
154bbd6d60aSBrian Feldman 			continue;
1559fe5fadaSRuslan Ermilov 		}
156bbd6d60aSBrian Feldman 
157bbd6d60aSBrian Feldman 		fprintf(f, "\tnode [ shape = octagon, fontsize = 10 ] {\n");
158bbd6d60aSBrian Feldman 		for (j = 0; j < ninfo->hooks; j++)
159bbd6d60aSBrian Feldman 			fprintf(f, "\t\t\"%jx.%s\" [ label = \"%s\" ];\n",
160bbd6d60aSBrian Feldman 			    (uintmax_t)nlist->nodeinfo[i].id,
161bbd6d60aSBrian Feldman 			    hlist->link[j].ourhook, hlist->link[j].ourhook);
162bbd6d60aSBrian Feldman 		fprintf(f, "\t};\n");
163bbd6d60aSBrian Feldman 
164bbd6d60aSBrian Feldman 		fprintf(f, "\t{\n\t\tedge [ weight = 2.0, style = bold ];\n");
165bbd6d60aSBrian Feldman 		for (j = 0; j < ninfo->hooks; j++)
166bbd6d60aSBrian Feldman 			fprintf(f, "\t\t\"%jx\" -- \"%jx.%s\";\n",
167bbd6d60aSBrian Feldman 			    (uintmax_t)nlist->nodeinfo[i].id,
168bbd6d60aSBrian Feldman 			    (uintmax_t)nlist->nodeinfo[i].id,
169bbd6d60aSBrian Feldman 			    hlist->link[j].ourhook);
170bbd6d60aSBrian Feldman 		fprintf(f, "\t};\n");
171bbd6d60aSBrian Feldman 
172bbd6d60aSBrian Feldman 		for (j = 0; j < ninfo->hooks; j++) {
173bbd6d60aSBrian Feldman 			/* Only print the edges going in one direction. */
174bbd6d60aSBrian Feldman 			if (hlist->link[j].nodeinfo.id > nlist->nodeinfo[i].id)
175bbd6d60aSBrian Feldman 				continue;
176bbd6d60aSBrian Feldman 			fprintf(f, "\t\"%jx.%s\" -- \"%jx.%s\";\n",
177bbd6d60aSBrian Feldman 			    (uintmax_t)nlist->nodeinfo[i].id,
178bbd6d60aSBrian Feldman 			    hlist->link[j].ourhook,
179bbd6d60aSBrian Feldman 			    (uintmax_t)hlist->link[j].nodeinfo.id,
180bbd6d60aSBrian Feldman 			    hlist->link[j].peerhook);
181bbd6d60aSBrian Feldman 		}
1829fe5fadaSRuslan Ermilov 		free(hlresp);
183bbd6d60aSBrian Feldman 	}
184bbd6d60aSBrian Feldman 
185bbd6d60aSBrian Feldman 	fprintf(f, "};\n");
186bbd6d60aSBrian Feldman 
1879fe5fadaSRuslan Ermilov 	free(nlresp);
188bbd6d60aSBrian Feldman 	if (f != stdout)
189bbd6d60aSBrian Feldman 		(void)fclose(f);
190bbd6d60aSBrian Feldman 	return (CMDRTN_OK);
191bbd6d60aSBrian Feldman error:
192bbd6d60aSBrian Feldman 	if (f != stdout)
193bbd6d60aSBrian Feldman 		(void)fclose(f);
194bbd6d60aSBrian Feldman 	return (CMDRTN_ERROR);
195bbd6d60aSBrian Feldman }
196