]> ruderich.org/simon Gitweb - linux-network-namespace-labs/linux-network-namespace-labs.git/commitdiff
Add support to generate dot files of the network
authorSimon Ruderich <simon@ruderich.org>
Fri, 1 Nov 2024 07:43:55 +0000 (08:43 +0100)
committerSimon Ruderich <simon@ruderich.org>
Fri, 1 Nov 2024 07:43:55 +0000 (08:43 +0100)
The resulting image (after running `dot`) isn't perfect but good enough
to get a quick overview of the network.

dot.go [new file with mode: 0644]
main.go

diff --git a/dot.go b/dot.go
new file mode 100644 (file)
index 0000000..c49c3bb
--- /dev/null
+++ b/dot.go
@@ -0,0 +1,68 @@
+// Write dot file showing the network architecture.
+
+// SPDX-License-Identifier: GPL-3.0-or-later
+// Copyright (C) 2024  Simon Ruderich
+
+package main
+
+import (
+       "bufio"
+       "fmt"
+       "html"
+       "os"
+       "strings"
+)
+
+func writeDot(cfg *Config, path string) error {
+       f, err := os.Create(path)
+       if err != nil {
+               return err
+       }
+       defer f.Close()
+       w := bufio.NewWriter(f)
+
+       fmt.Fprintf(w, "graph {\n")
+       fmt.Fprintf(w, "graph [nodesep=3]\n")
+
+       for _, node := range cfg.Nodes {
+               var as []string
+               as = append(as, html.EscapeString(node.Name)+"<br/>")
+               for _, x := range node.Loopbacks {
+                       as = append(as, fmt.Sprintf("&nbsp;<font point-size=\"10\">%s</font>&nbsp;<br/>",
+                               html.EscapeString(x.String())))
+               }
+               fmt.Fprintf(w, "%s [label=<%s>]\n",
+                       node.Name, strings.Join(as, ""))
+       }
+
+       for _, link := range cfg.Links {
+               var aas []string
+               for _, x := range link.A.Addrs {
+                       aas = append(aas, fmt.Sprintf("&nbsp;%s&nbsp;<br/>",
+                               html.EscapeString(x.Addr().String())))
+               }
+               var abs []string
+               for _, x := range link.B.Addrs {
+                       abs = append(abs, fmt.Sprintf("&nbsp;%s&nbsp;<br/>",
+                               html.EscapeString(x.Addr().String())))
+               }
+               fmt.Fprintf(w, "%s -- %s [taillabel=<%s>,headlabel=<%s>,labelfontsize=10]\n",
+                       link.A.Node.Name, link.B.Node.Name,
+                       strings.Join(aas, ""), strings.Join(abs, ""),
+               )
+       }
+
+       fmt.Fprintf(w, "}\n")
+
+       err = w.Flush()
+       if err != nil {
+               return err
+       }
+       err = f.Sync()
+       if err != nil {
+               return err
+       }
+       return nil
+}
+
+// vi: set noet ts=4 sw=4 sts=4:
diff --git a/main.go b/main.go
index a935b5cacf3f3e1823660f8c8c6da2789bd61464..5c1e9cc91a50b8a16c28d1a67bedaa50ec232e7a 100644 (file)
--- a/main.go
+++ b/main.go
@@ -18,9 +18,9 @@ import (
 )
 
 func main() {
-       if len(os.Args) != 2 {
+       if len(os.Args) != 2 && len(os.Args) != 3 {
                log.SetFlags(0)
-               log.Fatalf("usage: %s <config>", os.Args[0])
+               log.Fatalf("usage: %s <config> [<dot-output>]", os.Args[0])
        }
 
        cfg, err := LoadConfig(os.Args[1])
@@ -28,6 +28,14 @@ func main() {
                log.Fatalf("config %q: %v", os.Args[1], err)
        }
 
+       // Write dot file showing the network architecture
+       if len(os.Args) == 3 {
+               err := writeDot(cfg, os.Args[2])
+               if err != nil {
+                       log.Fatal(err)
+               }
+       }
+
        for _, node := range cfg.Nodes {
                log.Printf("Setting up node %q ...", node.Name)