| // 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() |
| } |
| } |