summaryrefslogtreecommitdiff
path: root/vendor/github.com/vishvananda/netlink/class_linux.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/vishvananda/netlink/class_linux.go')
-rw-r--r--vendor/github.com/vishvananda/netlink/class_linux.go145
1 files changed, 137 insertions, 8 deletions
diff --git a/vendor/github.com/vishvananda/netlink/class_linux.go b/vendor/github.com/vishvananda/netlink/class_linux.go
index a4997740e..31091e501 100644
--- a/vendor/github.com/vishvananda/netlink/class_linux.go
+++ b/vendor/github.com/vishvananda/netlink/class_linux.go
@@ -1,14 +1,34 @@
package netlink
import (
+ "bytes"
+ "encoding/binary"
+ "encoding/hex"
"errors"
+ "fmt"
"syscall"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
-// NOTE: function is in here because it uses other linux functions
+// Internal tc_stats representation in Go struct.
+// This is for internal uses only to deserialize the payload of rtattr.
+// After the deserialization, this should be converted into the canonical stats
+// struct, ClassStatistics, in case of statistics of a class.
+// Ref: struct tc_stats { ... }
+type tcStats struct {
+ Bytes uint64 // Number of enqueued bytes
+ Packets uint32 // Number of enqueued packets
+ Drops uint32 // Packets dropped because of lack of resources
+ Overlimits uint32 // Number of throttle events when this flow goes out of allocated bandwidth
+ Bps uint32 // Current flow byte rate
+ Pps uint32 // Current flow packet rate
+ Qlen uint32
+ Backlog uint32
+}
+
+// NewHtbClass NOTE: function is in here because it uses other linux functions
func NewHtbClass(attrs ClassAttrs, cattrs HtbClassAttrs) *HtbClass {
mtu := 1600
rate := cattrs.Rate / 8
@@ -126,7 +146,9 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(class.Type())))
options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
- if htb, ok := class.(*HtbClass); ok {
+ switch class.Type() {
+ case "htb":
+ htb := class.(*HtbClass)
opt := nl.TcHtbCopt{}
opt.Buffer = htb.Buffer
opt.Cbuffer = htb.Cbuffer
@@ -151,9 +173,18 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
return errors.New("HTB: failed to calculate ceil rate table")
}
opt.Ceil = tcceil
- nl.NewRtAttrChild(options, nl.TCA_HTB_PARMS, opt.Serialize())
- nl.NewRtAttrChild(options, nl.TCA_HTB_RTAB, SerializeRtab(rtab))
- nl.NewRtAttrChild(options, nl.TCA_HTB_CTAB, SerializeRtab(ctab))
+ options.AddRtAttr(nl.TCA_HTB_PARMS, opt.Serialize())
+ options.AddRtAttr(nl.TCA_HTB_RTAB, SerializeRtab(rtab))
+ options.AddRtAttr(nl.TCA_HTB_CTAB, SerializeRtab(ctab))
+ case "hfsc":
+ hfsc := class.(*HfscClass)
+ opt := nl.HfscCopt{}
+ opt.Rsc.Set(hfsc.Rsc.Attrs())
+ opt.Fsc.Set(hfsc.Fsc.Attrs())
+ opt.Usc.Set(hfsc.Usc.Attrs())
+ options.AddRtAttr(nl.TCA_HFSC_RSC, nl.SerializeHfscCurve(&opt.Rsc))
+ options.AddRtAttr(nl.TCA_HFSC_FSC, nl.SerializeHfscCurve(&opt.Fsc))
+ options.AddRtAttr(nl.TCA_HFSC_USC, nl.SerializeHfscCurve(&opt.Usc))
}
req.AddData(options)
return nil
@@ -197,9 +228,10 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
}
base := ClassAttrs{
- LinkIndex: int(msg.Ifindex),
- Handle: msg.Handle,
- Parent: msg.Parent,
+ LinkIndex: int(msg.Ifindex),
+ Handle: msg.Handle,
+ Parent: msg.Parent,
+ Statistics: nil,
}
var class Class
@@ -211,6 +243,8 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
switch classType {
case "htb":
class = &HtbClass{}
+ case "hfsc":
+ class = &HfscClass{}
default:
class = &GenericClass{ClassType: classType}
}
@@ -225,6 +259,26 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
if err != nil {
return nil, err
}
+ case "hfsc":
+ data, err := nl.ParseRouteAttr(attr.Value)
+ if err != nil {
+ return nil, err
+ }
+ _, err = parseHfscClassData(class, data)
+ if err != nil {
+ return nil, err
+ }
+ }
+ // For backward compatibility.
+ case nl.TCA_STATS:
+ base.Statistics, err = parseTcStats(attr.Value)
+ if err != nil {
+ return nil, err
+ }
+ case nl.TCA_STATS2:
+ base.Statistics, err = parseTcStats2(attr.Value)
+ if err != nil {
+ return nil, err
}
}
}
@@ -253,3 +307,78 @@ func parseHtbClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, erro
}
return detailed, nil
}
+
+func parseHfscClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, error) {
+ hfsc := class.(*HfscClass)
+ detailed := false
+ for _, datum := range data {
+ m1, d, m2 := nl.DeserializeHfscCurve(datum.Value).Attrs()
+ switch datum.Attr.Type {
+ case nl.TCA_HFSC_RSC:
+ hfsc.Rsc = ServiceCurve{m1: m1, d: d, m2: m2}
+ case nl.TCA_HFSC_FSC:
+ hfsc.Fsc = ServiceCurve{m1: m1, d: d, m2: m2}
+ case nl.TCA_HFSC_USC:
+ hfsc.Usc = ServiceCurve{m1: m1, d: d, m2: m2}
+ }
+ }
+ return detailed, nil
+}
+
+func parseTcStats(data []byte) (*ClassStatistics, error) {
+ buf := &bytes.Buffer{}
+ buf.Write(data)
+ native := nl.NativeEndian()
+ tcStats := &tcStats{}
+ if err := binary.Read(buf, native, tcStats); err != nil {
+ return nil, err
+ }
+
+ stats := NewClassStatistics()
+ stats.Basic.Bytes = tcStats.Bytes
+ stats.Basic.Packets = tcStats.Packets
+ stats.Queue.Qlen = tcStats.Qlen
+ stats.Queue.Backlog = tcStats.Backlog
+ stats.Queue.Drops = tcStats.Drops
+ stats.Queue.Overlimits = tcStats.Overlimits
+ stats.RateEst.Bps = tcStats.Bps
+ stats.RateEst.Pps = tcStats.Pps
+
+ return stats, nil
+}
+
+func parseGnetStats(data []byte, gnetStats interface{}) error {
+ buf := &bytes.Buffer{}
+ buf.Write(data)
+ native := nl.NativeEndian()
+ return binary.Read(buf, native, gnetStats)
+}
+
+func parseTcStats2(data []byte) (*ClassStatistics, error) {
+ rtAttrs, err := nl.ParseRouteAttr(data)
+ if err != nil {
+ return nil, err
+ }
+ stats := NewClassStatistics()
+ for _, datum := range rtAttrs {
+ switch datum.Attr.Type {
+ case nl.TCA_STATS_BASIC:
+ if err := parseGnetStats(datum.Value, stats.Basic); err != nil {
+ return nil, fmt.Errorf("Failed to parse ClassStatistics.Basic with: %v\n%s",
+ err, hex.Dump(datum.Value))
+ }
+ case nl.TCA_STATS_QUEUE:
+ if err := parseGnetStats(datum.Value, stats.Queue); err != nil {
+ return nil, fmt.Errorf("Failed to parse ClassStatistics.Queue with: %v\n%s",
+ err, hex.Dump(datum.Value))
+ }
+ case nl.TCA_STATS_RATE_EST:
+ if err := parseGnetStats(datum.Value, stats.RateEst); err != nil {
+ return nil, fmt.Errorf("Failed to parse ClassStatistics.RateEst with: %v\n%s",
+ err, hex.Dump(datum.Value))
+ }
+ }
+ }
+
+ return stats, nil
+}