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