func (self NamedPort) Stats() (PortStats, error) { ifinfo := syscall.IfInfomsg{ Index: int32(self.ifIndex), } if hub, err := nlgo.NewRtHub(); err != nil { return PortStats{}, err } else { defer hub.Close() req := syscall.NetlinkMessage{ Header: syscall.NlMsghdr{ Type: syscall.RTM_GETLINK, Flags: syscall.NLM_F_DUMP, }, } (*nlgo.IfInfoMessage)(&req).Set(ifinfo, nil) if res, err := hub.Sync(req); err != nil { return PortStats{}, err } else { for _, r := range res { switch r.Header.Type { case syscall.RTM_NEWLINK: msg := nlgo.IfInfoMessage(r) if msg.IfInfo().Index != int32(self.ifIndex) { // pass } else if attrs, err := msg.Attrs(); err != nil { return PortStats{}, err } else if blk := attrs.(nlgo.AttrMap).Get(nlgo.IFLA_STATS64); blk != nil { stat := []byte(blk.(nlgo.Binary)) s := (*nlgo.RtnlLinkStats64)(unsafe.Pointer(&stat[0])) ret := PortStats{ RxPackets: s.RxPackets, TxPackets: s.TxPackets, RxBytes: s.RxBytes, TxBytes: s.TxBytes, RxDropped: s.RxDropped, TxDropped: s.TxDropped, RxErrors: s.RxErrors, TxErrors: s.TxErrors, } if self.hatype == syscall.ARPHRD_ETHER { ret.Ethernet = &PortStatsEthernet{ RxFrameErr: s.RxFrameErrors, RxOverErr: s.RxOverErrors, RxCrcErr: s.RxCrcErrors, Collisions: s.Collisions, } } return ret, nil } } } } } return PortStats{}, fmt.Errorf("rtnetlink query failed") }
func (self *NamedPortManager) NetlinkListen(ev syscall.NetlinkMessage) { mtype := ev.Header.Type if mtype != syscall.RTM_NEWLINK && mtype != syscall.RTM_DELLINK { return // no concern } msg := nlgo.IfInfoMessage(ev) ifinfo := msg.IfInfo() evPort := &NamedPort{ ifIndex: uint32(ifinfo.Index), flags: ifinfo.Flags, fd: -1, lock: &sync.Mutex{}, rhub: self.rhub, } if attrs, err := msg.Attrs(); err != nil { log.Print(err) } else if amap, ok := attrs.(nlgo.AttrMap); !ok { log.Print("route link policy did not return attr map") } else { if t := amap.Get(nlgo.IFLA_IFNAME); t != nil { evPort.name = string(t.(nlgo.NulString)) } if t := amap.Get(nlgo.IFLA_MTU); t != nil { evPort.mtu = uint32(t.(nlgo.U32)) } if t := amap.Get(nlgo.IFLA_ADDRESS); t != nil { evPort.mac = []byte(t.(nlgo.Binary)) } } nl80211 := self.ghub.Family("nl80211") switch mtype { case syscall.RTM_NEWLINK: if port := self.ports[evPort.ifIndex]; port != nil { port.flags = ifinfo.Flags if len(evPort.name) > 0 { port.name = evPort.name } if evPort.mtu != 0 { port.mtu = evPort.mtu } if len(evPort.mac) != 0 { port.mac = evPort.mac } port.monitor <- true if err := port.Up(); err != nil { // maybe ready for up log.Print(err) } return } // query wiphy if res, err := self.ghub.Sync(nl80211.Request(nlgo.NL80211_CMD_GET_INTERFACE, syscall.NLM_F_DUMP, nil, nlgo.AttrSlice{ nlgo.Attr{ Header: syscall.NlAttr{ Type: nlgo.NL80211_ATTR_IFINDEX, }, Value: nlgo.U32(ifinfo.Index), }, }.Bytes())); err != nil { log.Print(err) } else { for _, r := range res { if r.Family.Name != "nl80211" { continue } if attrs, err := nlgo.Nl80211Policy.Parse(r.Body()); err != nil { log.Print(err) } else if amap, ok := attrs.(nlgo.AttrMap); !ok { log.Print("nl80211 attr policy error") } else { if evPort.ifIndex == uint32(amap.Get(nlgo.NL80211_ATTR_IFINDEX).(nlgo.U32)) { evPort.hasWiphy = true evPort.wiphy = uint32(amap.Get(nlgo.NL80211_ATTR_WIPHY).(nlgo.U32)) } } } } tracking := func(port *NamedPort) bool { for _, name := range self.trackingNames { if port.name == name { return true } } if port.hasWiphy { for _, wiphy := range self.trackingWiphy { if port.wiphy == wiphy { return true } } } for idx, _ := range self.ports { if idx == port.ifIndex { return true } } return false } if tracking(evPort) { port := evPort port.ingress = make(chan Frame) port.monitor = make(chan bool) self.ports[uint32(ifinfo.Index)] = port func() { if port.hasWiphy { for _, wiphy := range self.trackingWiphy { if wiphy == port.wiphy { return } } self.trackingWiphy = append(self.trackingWiphy, port.wiphy) } }() self.datapath.AddPort(port) port.monitor <- true if err := port.Up(); err != nil { // maybe ready for up log.Print(err) } } case syscall.RTM_DELLINK: if port, ok := self.ports[evPort.ifIndex]; ok && port != nil { port.Down() port.Close() delete(self.ports, evPort.ifIndex) } // for wiphy unplug if res, err := self.ghub.Sync(nl80211.DumpRequest(nlgo.NL80211_CMD_GET_WIPHY)); err != nil { log.Print(err) } else { var activeWiphy []uint32 for _, r := range res { if r.Family.Name != "nl80211" { continue } if attrs, err := nlgo.Nl80211Policy.Parse(r.Body()); err != nil { log.Print(err) } else { activeWiphy = append(activeWiphy, uint32(attrs.(nlgo.AttrMap).Get(nlgo.NL80211_ATTR_WIPHY).(nlgo.U32))) } } var trackingWiphy []uint32 for _, wiphy := range self.trackingWiphy { for _, active := range activeWiphy { if wiphy == active { trackingWiphy = append(trackingWiphy, wiphy) } } } self.trackingWiphy = trackingWiphy } } }