]> Cypherpunks repositories - gostls13.git/commitdiff
net: implement network interface API for Plan 9
authorChris McGee <sirnewton_01@yahoo.ca>
Thu, 29 Sep 2016 01:29:08 +0000 (21:29 -0400)
committerBrad Fitzpatrick <bradfitz@golang.org>
Wed, 12 Oct 2016 10:12:31 +0000 (10:12 +0000)
The new implementation parses the plan9 interface files
and builds Interface representations for the net package.

Updates #17218

Change-Id: I3199d18d9e96a17e922186c3abff1d7cd9cbec2e
Reviewed-on: https://go-review.googlesource.com/29963
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/net/interface.go
src/net/interface_plan9.go [new file with mode: 0644]
src/net/interface_stub.go

index 61ee0ce7c3a3aedd1f26b84a65c7ed6b826643e7..e36e8866466dd6c5b2eb475f68d0bae5f905e1ef 100644 (file)
@@ -10,7 +10,7 @@ import (
        "time"
 )
 
-// BUG(mikio): On NaCl and Plan9, methods and functions related to
+// BUG(mikio): On NaCl, methods and functions related to
 // Interface are not implemented.
 
 // BUG(mikio): On DragonFly BSD, NetBSD, OpenBSD and Solaris, the
diff --git a/src/net/interface_plan9.go b/src/net/interface_plan9.go
new file mode 100644 (file)
index 0000000..12d39db
--- /dev/null
@@ -0,0 +1,199 @@
+// 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.
+
+package net
+
+import (
+       "errors"
+       "os"
+)
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otherwise it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, error) {
+       if ifindex == 0 {
+               n, err := interfaceCount()
+               if err != nil {
+                       return nil, err
+               }
+               ifcs := make([]Interface, n)
+               for i := range ifcs {
+                       ifc, err := readInterface(i)
+                       if err != nil {
+                               return nil, err
+                       }
+                       ifcs[i] = *ifc
+               }
+               return ifcs, nil
+       }
+
+       ifc, err := readInterface(ifindex - 1)
+       if err != nil {
+               return nil, err
+       }
+       return []Interface{*ifc}, nil
+}
+
+func readInterface(i int) (*Interface, error) {
+       ifc := &Interface{
+               Index: i + 1,                        // Offset the index by one to suit the contract
+               Name:  netdir + "/ipifc/" + itoa(i), // Name is the full path to the interface path in plan9
+       }
+
+       ifcstat := ifc.Name + "/status"
+       ifcstatf, err := open(ifcstat)
+       if err != nil {
+               return nil, err
+       }
+       defer ifcstatf.close()
+
+       line, ok := ifcstatf.readLine()
+       if !ok {
+               return nil, errors.New("invalid interface status file: " + ifcstat)
+       }
+
+       fields := getFields(line)
+       if len(fields) < 4 {
+               return nil, errors.New("invalid interface status file: " + ifcstat)
+       }
+
+       device := fields[1]
+       mtustr := fields[3]
+
+       mtu, _, ok := dtoi(mtustr)
+       if !ok {
+               return nil, errors.New("invalid status file of interface: " + ifcstat)
+       }
+       ifc.MTU = mtu
+
+       // Not a loopback device
+       if device != "/dev/null" {
+               deviceaddrf, err := open(device + "/addr")
+               if err != nil {
+                       return nil, err
+               }
+               defer deviceaddrf.close()
+
+               line, ok = deviceaddrf.readLine()
+               if !ok {
+                       return nil, errors.New("invalid address file for interface: " + device + "/addr")
+               }
+
+               if len(line) > 0 && len(line)%2 == 0 {
+                       ifc.HardwareAddr = make([]byte, len(line)/2)
+                       var ok bool
+                       for i := range ifc.HardwareAddr {
+                               j := (i + 1) * 2
+                               ifc.HardwareAddr[i], ok = xtoi2(line[i*2:j], 0)
+                               if !ok {
+                                       ifc.HardwareAddr = ifc.HardwareAddr[:i]
+                                       break
+                               }
+                       }
+               }
+
+               ifc.Flags = FlagUp | FlagBroadcast | FlagMulticast
+       } else {
+               ifc.Flags = FlagUp | FlagMulticast | FlagLoopback
+       }
+
+       return ifc, nil
+}
+
+func interfaceCount() (int, error) {
+       d, err := os.Open(netdir + "/ipifc")
+       if err != nil {
+               return -1, err
+       }
+       defer d.Close()
+
+       names, err := d.Readdirnames(0)
+       if err != nil {
+               return -1, err
+       }
+
+       // Assumes that numbered files in ipifc are strictly
+       // the incrementing numbered directories for the
+       // interfaces
+       c := 0
+       for _, name := range names {
+               if _, _, ok := dtoi(name); !ok {
+                       continue
+               }
+               c++
+       }
+
+       return c, nil
+}
+
+// If the ifi is nil, interfaceAddrTable returns addresses for all
+// network interfaces. Otherwise it returns addresses for a specific
+// interface.
+func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
+       ifcs := []Interface{}
+       if ifi == nil {
+               var err error
+               ifcs, err = interfaceTable(0)
+               if err != nil {
+                       return nil, err
+               }
+       } else {
+               ifcs = []Interface{*ifi}
+       }
+
+       addrs := make([]Addr, len(ifcs))
+       for i, ifc := range ifcs {
+               status := ifc.Name + "/status"
+               statusf, err := open(status)
+               if err != nil {
+                       return nil, err
+               }
+               defer statusf.close()
+
+               line, ok := statusf.readLine()
+               line, ok = statusf.readLine()
+               if !ok {
+                       return nil, errors.New("cannot parse IP address for interface: " + status)
+               }
+
+               // This assumes only a single address for the interface.
+               fields := getFields(line)
+               if len(fields) < 1 {
+                       return nil, errors.New("cannot parse IP address for interface: " + status)
+               }
+               addr := fields[0]
+               ip := ParseIP(addr)
+               if ip == nil {
+                       return nil, errors.New("cannot parse IP address for interface: " + status)
+               }
+
+               // The mask is represented as CIDR relative to the IPv6 address.
+               // Plan 9 internal representation is always IPv6.
+               maskfld := fields[1]
+               maskfld = maskfld[1:]
+               pfxlen, _, ok := dtoi(maskfld)
+               if !ok {
+                       return nil, errors.New("cannot parse network mask for interface: " + status)
+               }
+               mask := CIDRMask(int(pfxlen), 128)
+
+               if ip.To4() != nil { // IPv4 or IPv6 IPv4-mapped address
+                       mask = CIDRMask(pfxlen-8*len(v4InV6Prefix), 8*IPv4len)
+               }
+               if ip.To16() != nil && ip.To4() == nil { // IPv6 address
+                       mask = CIDRMask(pfxlen, 8*IPv6len)
+               }
+
+               addrs[i] = &IPNet{IP: ip, Mask: mask}
+       }
+
+       return addrs, nil
+}
+
+// interfaceMulticastAddrTable returns addresses for a specific
+// interface.
+func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
+       return nil, nil
+}
index a4eff5329838935848bd8c914b3a8ad3b439d95b..3b0a1aeacf26d075155cce3c76173e5f09cbcd65 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build nacl plan9
+// +build nacl
 
 package net