blob: 5f16cedb1b2d8153766f63ee7103c19cf722ebf0 [file] [log] [blame]
// Copyright 2017 The Fuchsia 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 main
import (
"fmt"
"os"
"github.com/google/netstack/tcpip"
"app/context"
"fidl/bindings"
"garnet/public/lib/netstack/fidl/net_address"
"garnet/public/lib/netstack/fidl/netstack"
)
type netstackClientApp struct {
ctx *context.Context
netstack *netstack.Netstack_Proxy
}
func (a *netstackClientApp) printAll() {
ifaces, err := a.netstack.GetInterfaces()
if err != nil {
fmt.Print("ifconfig: failed to fetch interfaces\n")
return
}
for _, iface := range ifaces {
a.printIface(iface)
}
}
func (a *netstackClientApp) getIfaceByName(name string) *netstack.NetInterface {
ifaces, err := a.netstack.GetInterfaces()
if err != nil {
fmt.Print("ifconfig: failed to fetch interfaces\n")
return nil
}
for _, iface := range ifaces {
if iface.Name == name {
return &iface
}
}
return nil
}
func (a *netstackClientApp) printIface(iface netstack.NetInterface) {
stats, err := a.netstack.GetStats(iface.Id)
if err != nil {
fmt.Printf("ifconfig: failed to fetch stats for '%v'\n\n", iface.Name)
return
}
fmt.Printf("%s\tHWaddr %s\n", iface.Name, hwAddrToString(iface.Hwaddr))
fmt.Printf("\tinet addr:%s Bcast:%s Mask:%s\n", netAddrToString(iface.Addr), netAddrToString(iface.Broadaddr), netAddrToString(iface.Netmask))
for _, addr := range iface.Ipv6addrs {
// TODO: scopes
fmt.Printf("\tinet6 addr: %s/%d Scope:Link\n", netAddrToString(addr.Addr), addr.PrefixLen)
}
fmt.Printf("\t%s\n", flagsToString(iface.Flags))
fmt.Printf("\tRX packets:%d\n", stats.Rx.PktsTotal)
fmt.Printf("\tTX packets:%d\n", stats.Tx.PktsTotal)
fmt.Printf("\tRX bytes:%s TX bytes:%s\n",
bytesToString(stats.Rx.BytesTotal), bytesToString(stats.Tx.BytesTotal))
fmt.Printf("\n")
// TODO: more stats. MTU, RX/TX errors
}
func (a *netstackClientApp) setStatus(iface netstack.NetInterface, up bool) {
a.netstack.SetInterfaceStatus(iface.Id, up)
}
func hwAddrToString(hwaddr []uint8) string {
str := ""
for i := 0; i < len(hwaddr); i++ {
if i > 0 {
str += ":"
}
str += fmt.Sprintf("%x", hwaddr[i])
}
return str
}
func netAddrToString(addr net_address.NetAddress) string {
switch addr.Family {
case net_address.NetAddressFamily_Ipv4:
a := tcpip.Address(addr.Ipv4[:])
return fmt.Sprintf("%s", a)
case net_address.NetAddressFamily_Ipv6:
a := tcpip.Address(addr.Ipv6[:])
return fmt.Sprintf("%s", a)
}
return ""
}
func flagsToString(flags uint32) string {
str := ""
if flags&netstack.NetInterfaceFlagUp != 0 {
str += "UP"
}
return str
}
// bytesToString returns a human-friendly display of the given byte count.
// Values over 1K have an approximation appended in parentheses.
// bytesToString(42) => "42"
// bytesToString(42*1024 + 200) => "43208 (42.2 KB)"
func bytesToString(bytes uint64) string {
if bytes == 0 {
return "0"
}
units := "BKMGT"
unitSize := uint64(1)
unit := "B"
for i := 0; i+1 < len(units) && bytes >= unitSize*1024; i++ {
unitSize *= 1024
unit = string(units[i+1]) + "B"
}
if unitSize == 1 {
return fmt.Sprintf("%d", bytes)
} else {
value := float32(bytes) / float32(unitSize)
return fmt.Sprintf("%d (%.1f %s)", bytes, value, unit)
}
}
func usage() {
fmt.Printf("Usage:\n")
fmt.Printf(" %s [<interface>]\n", os.Args[0])
fmt.Printf(" %s [<interface>] [up|down]\n", os.Args[0])
}
func main() {
a := &netstackClientApp{ctx: context.CreateFromStartupInfo()}
r, p := a.netstack.NewRequest(bindings.GetAsyncWaiter())
a.netstack = p
defer a.netstack.Close()
a.ctx.ConnectToEnvService(r)
if len(os.Args) == 1 {
a.printAll()
return
}
iface := a.getIfaceByName(os.Args[1])
if iface == nil {
fmt.Printf("ifconfig: no such interface '%s'\n", os.Args[1])
return
}
if len(os.Args) == 2 {
a.printIface(*iface)
} else if len(os.Args) == 3 {
if os.Args[2] == "up" {
a.setStatus(*iface, true)
} else if os.Args[2] == "down" {
a.setStatus(*iface, false)
} else {
usage()
}
} else {
usage()
}
}