func (self NamedPort) Stats() (PortStats, error) { ifinfo := (*[syscall.SizeofIfInfomsg]byte)(unsafe.Pointer(&syscall.IfInfomsg{ Index: int32(self.ifIndex), }))[:] if hub, err := nlgo.NewRtHub(); err != nil { return PortStats{}, err } else { defer hub.Close() if res, err := hub.Request(syscall.RTM_GETLINK, syscall.NLM_F_DUMP, ifinfo, nil); err != nil { return PortStats{}, err } else { for _, r := range res { rIfinfo := (*syscall.IfInfomsg)(unsafe.Pointer(&r.Message.Data[0])) if rIfinfo.Index != int32(self.ifIndex) { continue } switch r.Message.Header.Type { case syscall.RTM_NEWLINK: if attrs, err := nlgo.RouteLinkPolicy.Parse(r.Message.Data[nlgo.NLMSG_ALIGN(syscall.SizeofIfInfomsg):]); 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 parse_attributes(data []byte) map[int]Attr { attrs := make(map[int]Attr, 0) for len(data) != 0 { attr_len := binary.LittleEndian.Uint16(data[0:2]) attr_type := binary.LittleEndian.Uint16(data[2:4]) attrs[int(attr_type)] = Attr{ int(attr_type), data[4:attr_len], } data = data[nlgo.NLMSG_ALIGN(int(attr_len)):] } return attrs }
func (self NamedPort) get6lowpanMac(addr net.IP) net.HardwareAddr { if msgs, err := self.rhub.Request( syscall.RTM_GETROUTE, syscall.NLM_F_REQUEST, (*[syscall.SizeofRtMsg]byte)(unsafe.Pointer(&syscall.RtMsg{ Family: syscall.AF_INET6, }))[:], nlgo.AttrSlice{ nlgo.Attr{ Header: syscall.NlAttr{ Type: syscall.RTA_DST, }, Value: nlgo.Binary(addr.To16()), }, }, ); err != nil { return nil } else { for _, msg := range msgs { if msg.Error != nil { continue } switch msg.Message.Header.Type { case syscall.RTM_NEWROUTE: if attr, err := nlgo.RoutePolicy.Parse(msg.Message.Data[nlgo.NLMSG_ALIGN(syscall.SizeofRtMsg):]); err != nil { return nil } else if gw := attr.(nlgo.AttrMap).Get(nlgo.RTA_GATEWAY); gw != nil { if mac := v6toMac(net.IP(gw.(nlgo.Binary))); mac != nil { return mac } } } } } if mac := v6toMac(addr); mac != nil { return mac } return nil }
func (self *NamedPortManager) RtListen(ev nlgo.RtMessage) { mtype := ev.Message.Header.Type if mtype != syscall.RTM_NEWLINK && mtype != syscall.RTM_DELLINK { return // no concern } ifinfo := (*syscall.IfInfomsg)(unsafe.Pointer(&ev.Message.Data[0])) evPort := &NamedPort{ ifIndex: uint32(ifinfo.Index), flags: ifinfo.Flags, fd: -1, lock: &sync.Mutex{}, rhub: self.rhub, } if attrs, err := nlgo.RouteLinkPolicy.Parse(ev.Message.Data[nlgo.NLMSG_ALIGN(syscall.SizeofIfInfomsg):]); 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)) } } 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.Request("nl80211", 1, 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), }, }); err != nil { log.Print(err) } else { for _, r := range res { if r.Error != nil { log.Print(r.Error) } if r.Family != "nl80211" { continue } if attrs, err := nlgo.Nl80211Policy.Parse(r.Payload); 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.Request("nl80211", 1, nlgo.NL80211_CMD_GET_WIPHY, syscall.NLM_F_DUMP, nil, nil); err != nil { log.Print(err) } else { var activeWiphy []uint32 for _, r := range res { if r.Family != "nl80211" { continue } if attrs, err := nlgo.Nl80211Policy.Parse(r.Payload); 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 } } }