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