in pkg/exporter/probe/nlqdisc/nlqdiscstats.go [299:386]
func parseMessage(msg netlink.Message) (QdiscInfo, error) {
var m QdiscInfo
var s TCStats
var s2 TCStats2
var sFq TCFqQdStats
/*
struct tcmsg {
unsigned char tcm_family;
unsigned char tcm__pad1;
unsigned short tcm__pad2;
int tcm_ifindex;
__u32 tcm_handle;
__u32 tcm_parent;
__u32 tcm_info;
};
*/
if len(msg.Data) < 20 {
return m, fmt.Errorf("short message, len=%d", len(msg.Data))
}
ifaceIdx := nlenc.Uint32(msg.Data[4:8])
m.Handle = nlenc.Uint32(msg.Data[8:12])
m.Parent = nlenc.Uint32(msg.Data[12:16])
if m.Parent == math.MaxUint32 {
m.Parent = 0
}
// The first 20 bytes are taken by tcmsg
attrs, err := netlink.UnmarshalAttributes(msg.Data[20:])
if err != nil {
return m, fmt.Errorf("failed to unmarshal attributes: %v", err)
}
for _, attr := range attrs {
switch attr.Type {
case TCAKind:
m.Kind = nlenc.String(attr.Data)
case TCAStats2:
sFq, err = parseTCFqQdStats(attr)
if err != nil {
return m, err
}
if sFq.GcFlows > 0 {
m.GcFlows = sFq.GcFlows
}
if sFq.Throttled > 0 {
m.Throttled = sFq.Throttled
}
if sFq.FlowsPlimit > 0 {
m.FlowsPlimit = sFq.FlowsPlimit
}
s2 = parseTCAStats2(attr)
m.Bytes = s2.Bytes
m.Packets = s2.Packets
m.Drops = s2.Drops
// requeues only available in TCAStats2, not in TCAStats
m.Requeues = s2.Requeues
m.Overlimits = s2.Overlimits
m.Qlen = s2.Qlen
m.Backlog = s2.Backlog
case TCAStats:
// Legacy
s = parseTCAStats(attr)
m.Bytes = s.Bytes
m.Packets = s.Packets
m.Drops = s.Drops
m.Overlimits = s.Overlimits
m.Qlen = s.Qlen
m.Backlog = s.Backlog
default:
// TODO: TCAOptions and TCAXStats
}
}
iface, err := net.InterfaceByIndex(int(ifaceIdx))
if err == nil {
m.IfaceName = iface.Name
}
return m, err
}