You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
3.6 KiB

  1. // Copyright 2016 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build solaris
  5. package lif
  6. import "unsafe"
  7. // A Link represents logical data link information.
  8. //
  9. // It also represents base information for logical network interface.
  10. // On Solaris, each logical network interface represents network layer
  11. // adjacency information and the interface has a only single network
  12. // address or address pair for tunneling. It's usual that multiple
  13. // logical network interfaces share the same logical data link.
  14. type Link struct {
  15. Name string // name, equivalent to IP interface name
  16. Index int // index, equivalent to IP interface index
  17. Type int // type
  18. Flags int // flags
  19. MTU int // maximum transmission unit, basically link MTU but may differ between IP address families
  20. Addr []byte // address
  21. }
  22. func (ll *Link) fetch(s uintptr) {
  23. var lifr lifreq
  24. for i := 0; i < len(ll.Name); i++ {
  25. lifr.Name[i] = int8(ll.Name[i])
  26. }
  27. ioc := int64(sysSIOCGLIFINDEX)
  28. if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
  29. ll.Index = int(nativeEndian.Uint32(lifr.Lifru[:4]))
  30. }
  31. ioc = int64(sysSIOCGLIFFLAGS)
  32. if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
  33. ll.Flags = int(nativeEndian.Uint64(lifr.Lifru[:8]))
  34. }
  35. ioc = int64(sysSIOCGLIFMTU)
  36. if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
  37. ll.MTU = int(nativeEndian.Uint32(lifr.Lifru[:4]))
  38. }
  39. switch ll.Type {
  40. case sysIFT_IPV4, sysIFT_IPV6, sysIFT_6TO4:
  41. default:
  42. ioc = int64(sysSIOCGLIFHWADDR)
  43. if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
  44. ll.Addr, _ = parseLinkAddr(lifr.Lifru[4:])
  45. }
  46. }
  47. }
  48. // Links returns a list of logical data links.
  49. //
  50. // The provided af must be an address family and name must be a data
  51. // link name. The zero value of af or name means a wildcard.
  52. func Links(af int, name string) ([]Link, error) {
  53. eps, err := newEndpoints(af)
  54. if len(eps) == 0 {
  55. return nil, err
  56. }
  57. defer func() {
  58. for _, ep := range eps {
  59. ep.close()
  60. }
  61. }()
  62. return links(eps, name)
  63. }
  64. func links(eps []endpoint, name string) ([]Link, error) {
  65. var lls []Link
  66. lifn := lifnum{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP}
  67. lifc := lifconf{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP}
  68. for _, ep := range eps {
  69. lifn.Family = uint16(ep.af)
  70. ioc := int64(sysSIOCGLIFNUM)
  71. if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifn)); err != nil {
  72. continue
  73. }
  74. if lifn.Count == 0 {
  75. continue
  76. }
  77. b := make([]byte, lifn.Count*sizeofLifreq)
  78. lifc.Family = uint16(ep.af)
  79. lifc.Len = lifn.Count * sizeofLifreq
  80. if len(lifc.Lifcu) == 8 {
  81. nativeEndian.PutUint64(lifc.Lifcu[:], uint64(uintptr(unsafe.Pointer(&b[0]))))
  82. } else {
  83. nativeEndian.PutUint32(lifc.Lifcu[:], uint32(uintptr(unsafe.Pointer(&b[0]))))
  84. }
  85. ioc = int64(sysSIOCGLIFCONF)
  86. if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifc)); err != nil {
  87. continue
  88. }
  89. nb := make([]byte, 32) // see LIFNAMSIZ in net/if.h
  90. for i := 0; i < int(lifn.Count); i++ {
  91. lifr := (*lifreq)(unsafe.Pointer(&b[i*sizeofLifreq]))
  92. for i := 0; i < 32; i++ {
  93. if lifr.Name[i] == 0 {
  94. nb = nb[:i]
  95. break
  96. }
  97. nb[i] = byte(lifr.Name[i])
  98. }
  99. llname := string(nb)
  100. nb = nb[:32]
  101. if isDupLink(lls, llname) || name != "" && name != llname {
  102. continue
  103. }
  104. ll := Link{Name: llname, Type: int(lifr.Type)}
  105. ll.fetch(ep.s)
  106. lls = append(lls, ll)
  107. }
  108. }
  109. return lls, nil
  110. }
  111. func isDupLink(lls []Link, name string) bool {
  112. for _, ll := range lls {
  113. if ll.Name == name {
  114. return true
  115. }
  116. }
  117. return false
  118. }