link.mx raw

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