1124271Sgreen 2124271Sgreen/* 3124271Sgreen * dot.c 4124271Sgreen * 5124271Sgreen * Copyright (c) 2004 Brian Fundakowski Feldman 6124271Sgreen * Copyright (c) 1996-1999 Whistle Communications, Inc. 7124271Sgreen * All rights reserved. 8124271Sgreen * 9124271Sgreen * Subject to the following obligations and disclaimer of warranty, use and 10124271Sgreen * redistribution of this software, in source or object code forms, with or 11124271Sgreen * without modifications are expressly permitted by Whistle Communications; 12124271Sgreen * provided, however, that: 13124271Sgreen * 1. Any and all reproductions of the source or object code must include the 14124271Sgreen * copyright notice above and the following disclaimer of warranties; and 15124271Sgreen * 2. No rights are granted, in any manner or form, to use Whistle 16124271Sgreen * Communications, Inc. trademarks, including the mark "WHISTLE 17124271Sgreen * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 18124271Sgreen * such appears in the above copyright notice or in the software. 19124271Sgreen * 20124271Sgreen * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 21124271Sgreen * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 22124271Sgreen * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 23124271Sgreen * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 24124271Sgreen * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 25124271Sgreen * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 26124271Sgreen * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 27124271Sgreen * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 28124271Sgreen * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 29124271Sgreen * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 30124271Sgreen * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 31124271Sgreen * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 32124271Sgreen * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 33124271Sgreen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34124271Sgreen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35124271Sgreen * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 36124271Sgreen * OF SUCH DAMAGE. 37124271Sgreen * 38124271Sgreen * $FreeBSD$ 39124271Sgreen */ 40124271Sgreen 41158882Sglebius#include <err.h> 42124271Sgreen#include <inttypes.h> 43158882Sglebius#include <netgraph.h> 44158882Sglebius#include <stdio.h> 45158882Sglebius#include <stdlib.h> 46158882Sglebius#include <unistd.h> 47124271Sgreen 48124271Sgreen#include "ngctl.h" 49124271Sgreen 50124271Sgreen#define UNNAMED "\\<unnamed\\>" 51124271Sgreen 52124271Sgreenstatic int DotCmd(int ac, char **av); 53124271Sgreen 54124271Sgreenconst struct ngcmd dot_cmd = { 55124271Sgreen DotCmd, 56124271Sgreen "dot [outputfile]", 57124271Sgreen "Produce a GraphViz (.dot) of the entire netgraph.", 58124271Sgreen "If no outputfile is specified, stdout will be assumed.", 59124271Sgreen { "graphviz", "confdot" } 60124271Sgreen}; 61124271Sgreen 62124271Sgreenstatic int 63124271SgreenDotCmd(int ac, char **av) 64124271Sgreen{ 65125115Sru struct ng_mesg *nlresp; 66125115Sru struct namelist *nlist; 67124271Sgreen FILE *f = stdout; 68125011Sru int ch; 69125011Sru u_int i; 70124271Sgreen 71124271Sgreen /* Get options */ 72124271Sgreen optind = 1; 73166529Skevlo while ((ch = getopt(ac, av, "")) != -1) { 74124271Sgreen switch (ch) { 75124271Sgreen case '?': 76124271Sgreen default: 77124271Sgreen return (CMDRTN_USAGE); 78124271Sgreen break; 79124271Sgreen } 80124271Sgreen } 81124271Sgreen ac -= optind; 82124271Sgreen av += optind; 83124271Sgreen 84124271Sgreen /* Get arguments */ 85124271Sgreen switch (ac) { 86124271Sgreen case 1: 87124271Sgreen f = fopen(av[0], "w"); 88124271Sgreen if (f == NULL) { 89124271Sgreen warn("Could not open %s for writing", av[0]); 90124271Sgreen return (CMDRTN_ERROR); 91124271Sgreen } 92124271Sgreen case 0: 93124271Sgreen break; 94124271Sgreen default: 95124271Sgreen if (f != stdout) 96124271Sgreen (void)fclose(f); 97124271Sgreen return (CMDRTN_USAGE); 98124271Sgreen } 99124271Sgreen 100124271Sgreen /* Get list of nodes */ 101124271Sgreen if (NgSendMsg(csock, ".", NGM_GENERIC_COOKIE, NGM_LISTNODES, NULL, 102124271Sgreen 0) < 0) { 103124271Sgreen warn("send listnodes msg"); 104124271Sgreen goto error; 105124271Sgreen } 106125115Sru if (NgAllocRecvMsg(csock, &nlresp, NULL) < 0) { 107124271Sgreen warn("recv listnodes msg"); 108124271Sgreen goto error; 109124271Sgreen } 110124271Sgreen 111125115Sru nlist = (struct namelist *)nlresp->data; 112124271Sgreen fprintf(f, "graph netgraph {\n"); 113124271Sgreen /* TODO: implement rank = same or subgraphs at some point */ 114124271Sgreen fprintf(f, "\tedge [ weight = 1.0 ];\n"); 115124271Sgreen fprintf(f, "\tnode [ shape = record, fontsize = 12 ] {\n"); 116124271Sgreen for (i = 0; i < nlist->numnames; i++) 117124271Sgreen fprintf(f, "\t\t\"%jx\" [ label = \"{%s:|{%s|[%jx]:}}\" ];\n", 118124271Sgreen (uintmax_t)nlist->nodeinfo[i].id, 119124271Sgreen nlist->nodeinfo[i].name[0] != '\0' ? 120124271Sgreen nlist->nodeinfo[i].name : UNNAMED, 121124271Sgreen nlist->nodeinfo[i].type, (uintmax_t)nlist->nodeinfo[i].id); 122124271Sgreen fprintf(f, "\t};\n"); 123124271Sgreen 124124271Sgreen fprintf(f, "\tsubgraph cluster_disconnected {\n"); 125124271Sgreen fprintf(f, "\t\tbgcolor = pink;\n"); 126124271Sgreen for (i = 0; i < nlist->numnames; i++) 127124271Sgreen if (nlist->nodeinfo[i].hooks == 0) 128124271Sgreen fprintf(f, "\t\t\"%jx\";\n", 129124271Sgreen (uintmax_t)nlist->nodeinfo[i].id); 130124271Sgreen fprintf(f, "\t};\n"); 131124271Sgreen 132124271Sgreen for (i = 0; i < nlist->numnames; i++) { 133125115Sru struct ng_mesg *hlresp; 134125115Sru struct hooklist *hlist; 135125115Sru struct nodeinfo *ninfo; 136124271Sgreen char path[NG_PATHSIZ]; 137125011Sru u_int j; 138124271Sgreen 139124271Sgreen (void)snprintf(path, sizeof(path), "[%jx]:", 140124271Sgreen (uintmax_t)nlist->nodeinfo[i].id); 141124271Sgreen 142124271Sgreen /* Get node info and hook list */ 143124271Sgreen if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, 144124271Sgreen NULL, 0) < 0) { 145125115Sru free(nlresp); 146124271Sgreen warn("send listhooks msg"); 147124271Sgreen goto error; 148124271Sgreen } 149125115Sru if (NgAllocRecvMsg(csock, &hlresp, NULL) < 0) { 150125115Sru free(nlresp); 151124271Sgreen warn("recv listhooks msg"); 152124271Sgreen goto error; 153124271Sgreen } 154124271Sgreen 155125115Sru hlist = (struct hooklist *)hlresp->data; 156125115Sru ninfo = &hlist->nodeinfo; 157125115Sru if (ninfo->hooks == 0) { 158125115Sru free(hlresp); 159124271Sgreen continue; 160125115Sru } 161124271Sgreen 162124271Sgreen fprintf(f, "\tnode [ shape = octagon, fontsize = 10 ] {\n"); 163124271Sgreen for (j = 0; j < ninfo->hooks; j++) 164124271Sgreen fprintf(f, "\t\t\"%jx.%s\" [ label = \"%s\" ];\n", 165124271Sgreen (uintmax_t)nlist->nodeinfo[i].id, 166124271Sgreen hlist->link[j].ourhook, hlist->link[j].ourhook); 167124271Sgreen fprintf(f, "\t};\n"); 168124271Sgreen 169124271Sgreen fprintf(f, "\t{\n\t\tedge [ weight = 2.0, style = bold ];\n"); 170124271Sgreen for (j = 0; j < ninfo->hooks; j++) 171124271Sgreen fprintf(f, "\t\t\"%jx\" -- \"%jx.%s\";\n", 172124271Sgreen (uintmax_t)nlist->nodeinfo[i].id, 173124271Sgreen (uintmax_t)nlist->nodeinfo[i].id, 174124271Sgreen hlist->link[j].ourhook); 175124271Sgreen fprintf(f, "\t};\n"); 176124271Sgreen 177124271Sgreen for (j = 0; j < ninfo->hooks; j++) { 178124271Sgreen /* Only print the edges going in one direction. */ 179124271Sgreen if (hlist->link[j].nodeinfo.id > nlist->nodeinfo[i].id) 180124271Sgreen continue; 181124271Sgreen fprintf(f, "\t\"%jx.%s\" -- \"%jx.%s\";\n", 182124271Sgreen (uintmax_t)nlist->nodeinfo[i].id, 183124271Sgreen hlist->link[j].ourhook, 184124271Sgreen (uintmax_t)hlist->link[j].nodeinfo.id, 185124271Sgreen hlist->link[j].peerhook); 186124271Sgreen } 187125115Sru free(hlresp); 188124271Sgreen } 189124271Sgreen 190124271Sgreen fprintf(f, "};\n"); 191124271Sgreen 192125115Sru free(nlresp); 193124271Sgreen if (f != stdout) 194124271Sgreen (void)fclose(f); 195124271Sgreen return (CMDRTN_OK); 196124271Sgreenerror: 197124271Sgreen if (f != stdout) 198124271Sgreen (void)fclose(f); 199124271Sgreen return (CMDRTN_ERROR); 200124271Sgreen} 201