2
0

hostmap.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. //go:build e2e_testing
  2. // +build e2e_testing
  3. package router
  4. import (
  5. "fmt"
  6. "net/netip"
  7. "sort"
  8. "strings"
  9. "github.com/slackhq/nebula"
  10. )
  11. type edge struct {
  12. from string
  13. to string
  14. dual bool
  15. }
  16. func renderHostmaps(controls ...*nebula.Control) string {
  17. var lines []*edge
  18. r := "graph TB\n"
  19. for _, c := range controls {
  20. sr, se := renderHostmap(c)
  21. r += sr
  22. for _, e := range se {
  23. add := true
  24. // Collapse duplicate edges into a bi-directionally connected edge
  25. for _, ge := range lines {
  26. if e.to == ge.from && e.from == ge.to {
  27. add = false
  28. ge.dual = true
  29. break
  30. }
  31. }
  32. if add {
  33. lines = append(lines, e)
  34. }
  35. }
  36. }
  37. for _, line := range lines {
  38. if line.dual {
  39. r += fmt.Sprintf("\t%v <--> %v\n", line.from, line.to)
  40. } else {
  41. r += fmt.Sprintf("\t%v --> %v\n", line.from, line.to)
  42. }
  43. }
  44. return r
  45. }
  46. func renderHostmap(c *nebula.Control) (string, []*edge) {
  47. var lines []string
  48. var globalLines []*edge
  49. crt := c.GetCertState().GetDefaultCertificate()
  50. clusterName := strings.Trim(crt.Name(), " ")
  51. clusterVpnIp := crt.Networks()[0].Addr()
  52. r := fmt.Sprintf("\tsubgraph %s[\"%s (%s)\"]\n", clusterName, clusterName, clusterVpnIp)
  53. hm := c.GetHostmap()
  54. hm.RLock()
  55. defer hm.RUnlock()
  56. // Draw the vpn to index nodes
  57. r += fmt.Sprintf("\t\tsubgraph %s.hosts[\"Hosts (vpn ip to index)\"]\n", clusterName)
  58. hosts := sortedHosts(hm.Hosts)
  59. for _, vpnIp := range hosts {
  60. hi := hm.Hosts[vpnIp]
  61. r += fmt.Sprintf("\t\t\t%v.%v[\"%v\"]\n", clusterName, vpnIp, vpnIp)
  62. lines = append(lines, fmt.Sprintf("%v.%v --> %v.%v", clusterName, vpnIp, clusterName, hi.GetLocalIndex()))
  63. rs := hi.GetRelayState()
  64. for _, relayIp := range rs.CopyRelayIps() {
  65. lines = append(lines, fmt.Sprintf("%v.%v --> %v.%v", clusterName, vpnIp, clusterName, relayIp))
  66. }
  67. for _, relayIp := range rs.CopyRelayForIdxs() {
  68. lines = append(lines, fmt.Sprintf("%v.%v --> %v.%v", clusterName, vpnIp, clusterName, relayIp))
  69. }
  70. }
  71. r += "\t\tend\n"
  72. // Draw the relay hostinfos
  73. if len(hm.Relays) > 0 {
  74. r += fmt.Sprintf("\t\tsubgraph %s.relays[\"Relays (relay index to hostinfo)\"]\n", clusterName)
  75. for relayIndex, hi := range hm.Relays {
  76. r += fmt.Sprintf("\t\t\t%v.%v[\"%v\"]\n", clusterName, relayIndex, relayIndex)
  77. lines = append(lines, fmt.Sprintf("%v.%v --> %v.%v", clusterName, relayIndex, clusterName, hi.GetLocalIndex()))
  78. }
  79. r += "\t\tend\n"
  80. }
  81. // Draw the local index to relay or remote index nodes
  82. r += fmt.Sprintf("\t\tsubgraph indexes.%s[\"Indexes (index to hostinfo)\"]\n", clusterName)
  83. indexes := sortedIndexes(hm.Indexes)
  84. for _, idx := range indexes {
  85. hi, ok := hm.Indexes[idx]
  86. if ok {
  87. r += fmt.Sprintf("\t\t\t%v.%v[\"%v (%v)\"]\n", clusterName, idx, idx, hi.GetVpnAddrs())
  88. remoteClusterName := strings.Trim(hi.GetCert().Certificate.Name(), " ")
  89. globalLines = append(globalLines, &edge{from: fmt.Sprintf("%v.%v", clusterName, idx), to: fmt.Sprintf("%v.%v", remoteClusterName, hi.GetRemoteIndex())})
  90. _ = hi
  91. }
  92. }
  93. r += "\t\tend\n"
  94. // Add the edges inside this host
  95. for _, line := range lines {
  96. r += fmt.Sprintf("\t\t%v\n", line)
  97. }
  98. r += "\tend\n"
  99. return r, globalLines
  100. }
  101. func sortedHosts(hosts map[netip.Addr]*nebula.HostInfo) []netip.Addr {
  102. keys := make([]netip.Addr, 0, len(hosts))
  103. for key := range hosts {
  104. keys = append(keys, key)
  105. }
  106. sort.SliceStable(keys, func(i, j int) bool {
  107. return keys[i].Compare(keys[j]) > 0
  108. })
  109. return keys
  110. }
  111. func sortedIndexes(indexes map[uint32]*nebula.HostInfo) []uint32 {
  112. keys := make([]uint32, 0, len(indexes))
  113. for key := range indexes {
  114. keys = append(keys, key)
  115. }
  116. sort.SliceStable(keys, func(i, j int) bool {
  117. return keys[i] > keys[j]
  118. })
  119. return keys
  120. }