From ab2409752fc8992a172e8caffa64fa19beafbcb7 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Tue, 29 Oct 2024 21:58:47 +0100 Subject: utils: routers --- utils/.gitignore | 1 + utils/Makefile | 15 +++++++- utils/ipam/ipam.go | 77 +++++++++++++++++++++++++++++++++---- utils/ipam/yaml_model/yaml_model.go | 10 ++--- utils/main.go | 37 +++++++++++++++++- utils/networks/networks.go | 14 +------ utils/routers/routers.go | 49 ++++++++++++++++++++++- 7 files changed, 175 insertions(+), 28 deletions(-) create mode 100644 utils/.gitignore (limited to 'utils') diff --git a/utils/.gitignore b/utils/.gitignore new file mode 100644 index 0000000..9487075 --- /dev/null +++ b/utils/.gitignore @@ -0,0 +1 @@ +utils diff --git a/utils/Makefile b/utils/Makefile index 77e67a3..409ef2d 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -1,5 +1,18 @@ +IPAM=../ansible/group_vars/all/ipam.yml + all: utils - go run main.go > ../ansible/group_vars/all/ipam.tmp.dot && dot -Tpng ../ansible/group_vars/all/ipam.tmp.dot > ../ansible/group_vars/all/ipam.tmp.png + +networks: ../ansible/group_vars/all/networks.tmp.png +routers: ../ansible/group_vars/all/routers.tmp.png + +%.png:%.dot + dot -Tpng $< > $@ + +../ansible/group_vars/all/networks.tmp.dot: $(IPAM) + go run main.go networks $< > $@ + +../ansible/group_vars/all/routers.tmp.dot: $(IPAM) + go run main.go routers $< > $@ utils: go build diff --git a/utils/ipam/ipam.go b/utils/ipam/ipam.go index faec6e7..d61fa3e 100644 --- a/utils/ipam/ipam.go +++ b/utils/ipam/ipam.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "net/netip" + "slices" "utils/ipam/yaml_model" ) @@ -14,18 +15,25 @@ func LoadIpam(bs []byte) (*Ipam, error) { return nil, err } - ipam_, err := processNetworks(parsed.Ipam6.Networks) + ipam := Ipam{} + err = processNetworks(parsed.Ipam6.Networks, &ipam) if err != nil { return nil, err } - ipam_.ResolveParents() + err = processRouters(parsed.Routers, &ipam) + if err != nil { + return nil, err + } + + ipam.ResolveParents() - return ipam_, nil + return &ipam, nil } type Ipam struct { Networks []*Network + Routers []*Router } func contains(a, b netip.Prefix) bool { @@ -89,14 +97,14 @@ type networkHost struct { address netip.Addr } -func processNetworks(networks map[string]yaml_model.Network6Yaml) (*Ipam, error) { +func processNetworks(networks map[string]yaml_model.Network6Yaml, ipam *Ipam) error { var ns []*Network for name, net := range networks { log.Printf("Processing net %v\n", name) prefix, err := netip.ParsePrefix(net.Range) if err != nil { - return nil, fmt.Errorf("error parsing net range: %v", err) + return fmt.Errorf("error parsing net range: %v", err) } log.Printf("prefix: %s", prefix.String()) @@ -104,7 +112,7 @@ func processNetworks(networks map[string]yaml_model.Network6Yaml) (*Ipam, error) for hostname, a := range net.Hosts { addr, err := netip.ParseAddr(a) if err != nil { - return nil, fmt.Errorf("network: %s, unable to parse host address %s", n.Name, a) + return fmt.Errorf("network: %s, unable to parse host address %s", n.Name, a) } n.hosts = append(n.hosts, networkHost{ @@ -116,5 +124,60 @@ func processNetworks(networks map[string]yaml_model.Network6Yaml) (*Ipam, error) ns = append(ns, &n) } - return &Ipam{Networks: ns}, nil + ipam.Networks = ns + return nil +} + +type Router struct { + Name string + As string + Peers []Peer +} + +func (r *Router) Compare(other *Router) int { + return cmp.Compare(r.Name, other.Name) +} + +type Peer struct { + Name string + /// Router is set if this is a known peer + Router *Router + + As string +} + +func processRouters(routers map[string]yaml_model.Router, ipam *Ipam) error { + var rs []*Router + rsIndex := make(map[string]*Router) + for name, router := range routers { + r := &Router{ + Name: name, + As: router.As, + } + + rs = append(rs, r) + rsIndex[name] = r + } + + for _, r := range rs { + router := routers[r.Name] + + for name, peer := range router.Peers { + remote := rsIndex[name] + + r.Peers = append(r.Peers, Peer{ + Name: name, + Router: remote, + As: peer.As, + }) + } + } + + compare := func(a *Router, b *Router) int { + return a.Compare(b) + } + + ipam.Routers = slices.SortedStableFunc(slices.Values(rs), compare) + + return nil } diff --git a/utils/ipam/yaml_model/yaml_model.go b/utils/ipam/yaml_model/yaml_model.go index 6e5b0f8..4109e12 100644 --- a/utils/ipam/yaml_model/yaml_model.go +++ b/utils/ipam/yaml_model/yaml_model.go @@ -3,8 +3,8 @@ package yaml_model import "gopkg.in/yaml.v3" type Ipam struct { - Ipam6 Ipam6 `yaml:"ipam6,omitempty"` - Routers []Router `yaml:"routers,omitempty"` + Ipam6 Ipam6 `yaml:"ipam6,omitempty"` + Routers map[string]Router `yaml:"routers,omitempty"` } type Ipam6 struct { @@ -17,12 +17,12 @@ type Network6Yaml struct { } type Router struct { - As string `yaml:"as,omitempty"` - Peer []Peer `yaml:"peer,omitempty"` + As string `yaml:"as,omitempty"` + Peers map[string]Peer `yaml:"peers,omitempty"` } type Peer struct { - Name string `yaml:"name"` + As string `yaml:"as"` } func Parse(bs []byte) (Ipam, error) { diff --git a/utils/main.go b/utils/main.go index af3a4a7..32f9682 100644 --- a/utils/main.go +++ b/utils/main.go @@ -3,13 +3,48 @@ package main import ( "fmt" "os" + Ipam "utils/ipam" "utils/networks" + "utils/routers" ) func main() { - err := networks.RunNetworks() + if len(os.Args) != 3 { + _, _ = fmt.Fprintf(os.Stderr, "Usage: %s IPAM-FILE PICTURE\n", os.Args[0]) + os.Exit(1) + } + + ipam, err := loadIpam() + if err != nil { + return + } + + if os.Args[1] == "networks" { + err = networks.RunNetworks(ipam) + } else if os.Args[1] == "routers" { + err = routers.RunRouters(ipam) + } else { + _, _ = fmt.Fprintf(os.Stderr, "Unknown command: %s\n", os.Args[2]) + os.Exit(1) + } + if err != nil { _, _ = fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) } } + +func loadIpam() (*Ipam.Ipam, error) { + ipamYaml := os.Args[2] + bs, err := os.ReadFile(ipamYaml) + if err != nil { + return nil, err + } + + ipam, err := Ipam.LoadIpam(bs) + if err != nil { + return nil, err + } + + return ipam, nil +} diff --git a/utils/networks/networks.go b/utils/networks/networks.go index f667f05..9ecf256 100644 --- a/utils/networks/networks.go +++ b/utils/networks/networks.go @@ -2,23 +2,11 @@ package networks import ( "fmt" - "os" "slices" Ipam "utils/ipam" ) -func RunNetworks() error { - ipamYaml := "../ansible/group_vars/all/ipam.yml" - bs, err := os.ReadFile(ipamYaml) - if err != nil { - return err - } - - ipam, err := Ipam.LoadIpam(bs) - if err != nil { - return err - } - +func RunNetworks(ipam *Ipam.Ipam) error { networks := slices.SortedFunc(slices.Values(ipam.Networks), Ipam.CompareNetwork) roots := slices.SortedFunc(slices.Values(ipam.FindRoots()), Ipam.CompareNetwork) diff --git a/utils/routers/routers.go b/utils/routers/routers.go index 0afb355..24d25e3 100644 --- a/utils/routers/routers.go +++ b/utils/routers/routers.go @@ -1,4 +1,51 @@ package routers -type Routers struct { +import ( + "fmt" + Ipam "utils/ipam" +) + +func RunRouters(ipam *Ipam.Ipam) error { + routers := ipam.Routers + + fmt.Printf("digraph {\n") + //fmt.Printf(" layout=dot\n") + //fmt.Printf(" layout=twopi\n") + fmt.Printf(" layout=fdp\n") + //fmt.Printf(" layout=circo\n") + //fmt.Printf(" layout=neato\n") + //fmt.Printf(" ranksep=3\n") + //fmt.Printf(" ratio=auto\n") + //fmt.Printf(" rankdir=LR\n") + //fmt.Printf(" rankdir=RL\n") + fmt.Printf(" rankdir=TB\n") + //fmt.Printf(" sep=3\n") + //fmt.Printf(" overlap_scaling=-10\n") + fmt.Printf("node [len=10];") + fmt.Printf("node [shape=box];") + fmt.Printf("overlap=false") + + fmt.Printf("\n") + fmt.Printf(" # Nodes\n") + for _, r := range routers { + fmt.Printf(" %s [ label = \"%s\"];\n", r.Name, r.Name) + } + + fmt.Printf("\n") + fmt.Printf(" # Connections\n") + for _, n := range routers { + fmt.Printf(" %s [ root = true ];\n", n.Name) + } + + fmt.Printf("\n") + fmt.Printf(" # Peers\n") + for _, r := range routers { + for _, p := range r.Peers { + fmt.Printf(" %s -> %s", r.Name, p.Name) + fmt.Printf(";\n") + } + } + fmt.Printf("}\n") + + return nil } -- cgit v1.2.3