172 lines
3.2 KiB
Go
172 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type RouteAttrs map[string]string
|
|
|
|
type RoutePoint struct {
|
|
performLookup bool
|
|
attrs RouteAttrs
|
|
}
|
|
|
|
type RouteEdgeKey struct {
|
|
src string
|
|
dest string
|
|
}
|
|
|
|
type RouteEdgeValue struct {
|
|
label []string
|
|
attrs RouteAttrs
|
|
}
|
|
|
|
type RouteGraph struct {
|
|
points map[string]RoutePoint
|
|
edges map[RouteEdgeKey]RouteEdgeValue
|
|
}
|
|
|
|
func makeRouteGraph() RouteGraph {
|
|
return RouteGraph{
|
|
points: make(map[string]RoutePoint),
|
|
edges: make(map[RouteEdgeKey]RouteEdgeValue),
|
|
}
|
|
}
|
|
|
|
func makeRoutePoint() RoutePoint {
|
|
return RoutePoint{
|
|
performLookup: false,
|
|
attrs: make(RouteAttrs),
|
|
}
|
|
}
|
|
|
|
func makeRouteEdgeValue() RouteEdgeValue {
|
|
return RouteEdgeValue{
|
|
label: []string{},
|
|
attrs: make(RouteAttrs),
|
|
}
|
|
}
|
|
|
|
func (graph *RouteGraph) attrsToString(attrs RouteAttrs) string {
|
|
if len(attrs) == 0 {
|
|
return ""
|
|
}
|
|
|
|
result := ""
|
|
isFirst := true
|
|
for k, v := range attrs {
|
|
if isFirst {
|
|
isFirst = false
|
|
} else {
|
|
result += ","
|
|
}
|
|
result += graph.escape(k) + "=" + graph.escape(v) + ""
|
|
}
|
|
|
|
return "[" + result + "]"
|
|
}
|
|
|
|
func (graph *RouteGraph) escape(s string) string {
|
|
result, err := json.Marshal(s)
|
|
if err != nil {
|
|
return err.Error()
|
|
} else {
|
|
return string(result)
|
|
}
|
|
}
|
|
|
|
func (graph *RouteGraph) AddEdge(src string, dest string, label string, attrs RouteAttrs) {
|
|
// Add edges with same src/dest separately, multiple edges with same src/dest could exist
|
|
edge := RouteEdgeKey{
|
|
src: src,
|
|
dest: dest,
|
|
}
|
|
|
|
newValue, exists := graph.edges[edge]
|
|
if !exists {
|
|
newValue = makeRouteEdgeValue()
|
|
}
|
|
|
|
newValue.label = append(newValue.label, label)
|
|
for k, v := range attrs {
|
|
newValue.attrs[k] = v
|
|
}
|
|
|
|
graph.edges[edge] = newValue
|
|
}
|
|
|
|
func (graph *RouteGraph) AddPoint(name string, performLookup bool, attrs RouteAttrs) {
|
|
newValue, exists := graph.points[name]
|
|
if !exists {
|
|
newValue = makeRoutePoint()
|
|
}
|
|
|
|
newValue.performLookup = performLookup
|
|
for k, v := range attrs {
|
|
newValue.attrs[k] = v
|
|
}
|
|
|
|
graph.points[name] = newValue
|
|
}
|
|
|
|
func (graph *RouteGraph) GetEdge(src string, dest string) *RouteEdgeValue {
|
|
key := RouteEdgeKey{
|
|
src: src,
|
|
dest: dest,
|
|
}
|
|
value, ok := graph.edges[key]
|
|
if ok {
|
|
return &value
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (graph *RouteGraph) GetPoint(name string) *RoutePoint {
|
|
value, ok := graph.points[name]
|
|
if ok {
|
|
return &value
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (graph *RouteGraph) ToGraphviz() string {
|
|
var result string
|
|
|
|
asnCache := make(ASNCache)
|
|
|
|
for name, value := range graph.points {
|
|
var representation string
|
|
|
|
if value.performLookup {
|
|
representation = asnCache.Lookup(name)
|
|
} else {
|
|
representation = name
|
|
}
|
|
|
|
attrsCopy := value.attrs
|
|
if attrsCopy == nil {
|
|
attrsCopy = make(RouteAttrs)
|
|
}
|
|
attrsCopy["label"] = representation
|
|
|
|
result += fmt.Sprintf("%s %s;\n", graph.escape(name), graph.attrsToString(value.attrs))
|
|
}
|
|
|
|
for key, value := range graph.edges {
|
|
attrsCopy := value.attrs
|
|
if attrsCopy == nil {
|
|
attrsCopy = make(RouteAttrs)
|
|
}
|
|
if len(value.label) > 0 {
|
|
attrsCopy["label"] = strings.Join(value.label, "\n")
|
|
}
|
|
result += fmt.Sprintf("%s -> %s %s;\n", graph.escape(key.src), graph.escape(key.dest), graph.attrsToString(attrsCopy))
|
|
}
|
|
|
|
return "digraph {\n" + result + "}\n"
|
|
}
|