link.go 3.7 KB

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