Example #1
0
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")
}
Example #2
0
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
		}
	}
}