mirror of
https://github.com/vishvananda/netlink.git
synced 2025-09-27 12:12:09 +08:00
enable rule statistic and time statistic for flower actions
This commit is contained in:

committed by
Alessandro Boch

parent
004274e828
commit
0ced838538
2
class.go
2
class.go
@@ -47,6 +47,7 @@ type ClassStatistics struct {
|
|||||||
Basic *GnetStatsBasic
|
Basic *GnetStatsBasic
|
||||||
Queue *GnetStatsQueue
|
Queue *GnetStatsQueue
|
||||||
RateEst *GnetStatsRateEst
|
RateEst *GnetStatsRateEst
|
||||||
|
BasicHw *GnetStatsBasic // Hardward statistics added in kernel 4.20
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClassStatistics Construct a ClassStatistics struct which fields are all initialized by 0.
|
// NewClassStatistics Construct a ClassStatistics struct which fields are all initialized by 0.
|
||||||
@@ -55,6 +56,7 @@ func NewClassStatistics() *ClassStatistics {
|
|||||||
Basic: &GnetStatsBasic{},
|
Basic: &GnetStatsBasic{},
|
||||||
Queue: &GnetStatsQueue{},
|
Queue: &GnetStatsQueue{},
|
||||||
RateEst: &GnetStatsRateEst{},
|
RateEst: &GnetStatsRateEst{},
|
||||||
|
BasicHw: &GnetStatsBasic{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -388,6 +388,11 @@ func parseTcStats2(data []byte) (*ClassStatistics, error) {
|
|||||||
return nil, fmt.Errorf("Failed to parse ClassStatistics.RateEst with: %v\n%s",
|
return nil, fmt.Errorf("Failed to parse ClassStatistics.RateEst with: %v\n%s",
|
||||||
err, hex.Dump(datum.Value))
|
err, hex.Dump(datum.Value))
|
||||||
}
|
}
|
||||||
|
case nl.TCA_STATS_BASIC_HW:
|
||||||
|
if err := parseGnetStats(datum.Value, stats.BasicHw); err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to parse ClassStatistics.BasicHw with: %v\n%s",
|
||||||
|
err, hex.Dump(datum.Value))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
filter.go
15
filter.go
@@ -123,12 +123,27 @@ type ActionAttrs struct {
|
|||||||
Action TcAct
|
Action TcAct
|
||||||
Refcnt int
|
Refcnt int
|
||||||
Bindcnt int
|
Bindcnt int
|
||||||
|
Statistics *ActionStatistic
|
||||||
|
Timestamp *ActionTimestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q ActionAttrs) String() string {
|
func (q ActionAttrs) String() string {
|
||||||
return fmt.Sprintf("{Index: %d, Capab: %x, Action: %s, Refcnt: %d, Bindcnt: %d}", q.Index, q.Capab, q.Action.String(), q.Refcnt, q.Bindcnt)
|
return fmt.Sprintf("{Index: %d, Capab: %x, Action: %s, Refcnt: %d, Bindcnt: %d}", q.Index, q.Capab, q.Action.String(), q.Refcnt, q.Bindcnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ActionTimestamp struct {
|
||||||
|
Installed uint64
|
||||||
|
LastUsed uint64
|
||||||
|
Expires uint64
|
||||||
|
FirstUsed uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t ActionTimestamp) String() string {
|
||||||
|
return fmt.Sprintf("Installed %d LastUsed %d Expires %d FirstUsed %d", t.Installed, t.LastUsed, t.Expires, t.FirstUsed)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ActionStatistic ClassStatistics
|
||||||
|
|
||||||
// Action represents an action in any supported filter.
|
// Action represents an action in any supported filter.
|
||||||
type Action interface {
|
type Action interface {
|
||||||
Attrs() *ActionAttrs
|
Attrs() *ActionAttrs
|
||||||
|
@@ -528,6 +528,14 @@ func toAttrs(tcgen *nl.TcGen, attrs *ActionAttrs) {
|
|||||||
attrs.Bindcnt = int(tcgen.Bindcnt)
|
attrs.Bindcnt = int(tcgen.Bindcnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toTimeStamp(tcf *nl.Tcf) *ActionTimestamp {
|
||||||
|
return &ActionTimestamp{
|
||||||
|
Installed: tcf.Install,
|
||||||
|
LastUsed: tcf.LastUse,
|
||||||
|
Expires: tcf.Expires,
|
||||||
|
FirstUsed: tcf.FirstUse}
|
||||||
|
}
|
||||||
|
|
||||||
func encodePolice(attr *nl.RtAttr, action *PoliceAction) error {
|
func encodePolice(attr *nl.RtAttr, action *PoliceAction) error {
|
||||||
var rtab [256]uint32
|
var rtab [256]uint32
|
||||||
var ptab [256]uint32
|
var ptab [256]uint32
|
||||||
@@ -748,6 +756,8 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
|
|||||||
for _, table := range tables {
|
for _, table := range tables {
|
||||||
var action Action
|
var action Action
|
||||||
var actionType string
|
var actionType string
|
||||||
|
var actionnStatistic *ActionStatistic
|
||||||
|
var actionTimestamp *ActionTimestamp
|
||||||
aattrs, err := nl.ParseRouteAttr(table.Value)
|
aattrs, err := nl.ParseRouteAttr(table.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -795,7 +805,11 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
|
|||||||
toAttrs(&mirred.TcGen, action.Attrs())
|
toAttrs(&mirred.TcGen, action.Attrs())
|
||||||
action.(*MirredAction).Ifindex = int(mirred.Ifindex)
|
action.(*MirredAction).Ifindex = int(mirred.Ifindex)
|
||||||
action.(*MirredAction).MirredAction = MirredAct(mirred.Eaction)
|
action.(*MirredAction).MirredAction = MirredAct(mirred.Eaction)
|
||||||
|
case nl.TCA_MIRRED_TM:
|
||||||
|
tcTs := nl.DeserializeTcf(adatum.Value)
|
||||||
|
actionTimestamp = toTimeStamp(tcTs)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "tunnel_key":
|
case "tunnel_key":
|
||||||
switch adatum.Attr.Type {
|
switch adatum.Attr.Type {
|
||||||
case nl.TCA_TUNNEL_KEY_PARMS:
|
case nl.TCA_TUNNEL_KEY_PARMS:
|
||||||
@@ -811,6 +825,9 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
|
|||||||
action.(*TunnelKeyAction).DstAddr = adatum.Value[:]
|
action.(*TunnelKeyAction).DstAddr = adatum.Value[:]
|
||||||
case nl.TCA_TUNNEL_KEY_ENC_DST_PORT:
|
case nl.TCA_TUNNEL_KEY_ENC_DST_PORT:
|
||||||
action.(*TunnelKeyAction).DestPort = ntohs(adatum.Value)
|
action.(*TunnelKeyAction).DestPort = ntohs(adatum.Value)
|
||||||
|
case nl.TCA_TUNNEL_KEY_TM:
|
||||||
|
tcTs := nl.DeserializeTcf(adatum.Value)
|
||||||
|
actionTimestamp = toTimeStamp(tcTs)
|
||||||
}
|
}
|
||||||
case "skbedit":
|
case "skbedit":
|
||||||
switch adatum.Attr.Type {
|
switch adatum.Attr.Type {
|
||||||
@@ -833,6 +850,9 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
|
|||||||
case nl.TCA_SKBEDIT_QUEUE_MAPPING:
|
case nl.TCA_SKBEDIT_QUEUE_MAPPING:
|
||||||
mapping := native.Uint16(adatum.Value[0:2])
|
mapping := native.Uint16(adatum.Value[0:2])
|
||||||
action.(*SkbEditAction).QueueMapping = &mapping
|
action.(*SkbEditAction).QueueMapping = &mapping
|
||||||
|
case nl.TCA_SKBEDIT_TM:
|
||||||
|
tcTs := nl.DeserializeTcf(adatum.Value)
|
||||||
|
actionTimestamp = toTimeStamp(tcTs)
|
||||||
}
|
}
|
||||||
case "bpf":
|
case "bpf":
|
||||||
switch adatum.Attr.Type {
|
switch adatum.Attr.Type {
|
||||||
@@ -843,6 +863,9 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
|
|||||||
action.(*BpfAction).Fd = int(native.Uint32(adatum.Value[0:4]))
|
action.(*BpfAction).Fd = int(native.Uint32(adatum.Value[0:4]))
|
||||||
case nl.TCA_ACT_BPF_NAME:
|
case nl.TCA_ACT_BPF_NAME:
|
||||||
action.(*BpfAction).Name = string(adatum.Value[:len(adatum.Value)-1])
|
action.(*BpfAction).Name = string(adatum.Value[:len(adatum.Value)-1])
|
||||||
|
case nl.TCA_ACT_BPF_TM:
|
||||||
|
tcTs := nl.DeserializeTcf(adatum.Value)
|
||||||
|
actionTimestamp = toTimeStamp(tcTs)
|
||||||
}
|
}
|
||||||
case "connmark":
|
case "connmark":
|
||||||
switch adatum.Attr.Type {
|
switch adatum.Attr.Type {
|
||||||
@@ -851,6 +874,9 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
|
|||||||
action.(*ConnmarkAction).ActionAttrs = ActionAttrs{}
|
action.(*ConnmarkAction).ActionAttrs = ActionAttrs{}
|
||||||
toAttrs(&connmark.TcGen, action.Attrs())
|
toAttrs(&connmark.TcGen, action.Attrs())
|
||||||
action.(*ConnmarkAction).Zone = connmark.Zone
|
action.(*ConnmarkAction).Zone = connmark.Zone
|
||||||
|
case nl.TCA_CONNMARK_TM:
|
||||||
|
tcTs := nl.DeserializeTcf(adatum.Value)
|
||||||
|
actionTimestamp = toTimeStamp(tcTs)
|
||||||
}
|
}
|
||||||
case "csum":
|
case "csum":
|
||||||
switch adatum.Attr.Type {
|
switch adatum.Attr.Type {
|
||||||
@@ -859,6 +885,9 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
|
|||||||
action.(*CsumAction).ActionAttrs = ActionAttrs{}
|
action.(*CsumAction).ActionAttrs = ActionAttrs{}
|
||||||
toAttrs(&csum.TcGen, action.Attrs())
|
toAttrs(&csum.TcGen, action.Attrs())
|
||||||
action.(*CsumAction).UpdateFlags = CsumUpdateFlags(csum.UpdateFlags)
|
action.(*CsumAction).UpdateFlags = CsumUpdateFlags(csum.UpdateFlags)
|
||||||
|
case nl.TCA_CSUM_TM:
|
||||||
|
tcTs := nl.DeserializeTcf(adatum.Value)
|
||||||
|
actionTimestamp = toTimeStamp(tcTs)
|
||||||
}
|
}
|
||||||
case "gact":
|
case "gact":
|
||||||
switch adatum.Attr.Type {
|
switch adatum.Attr.Type {
|
||||||
@@ -868,13 +897,24 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
|
|||||||
if action.Attrs().Action.String() == "goto" {
|
if action.Attrs().Action.String() == "goto" {
|
||||||
action.(*GenericAction).Chain = TC_ACT_EXT_VAL_MASK & gen.Action
|
action.(*GenericAction).Chain = TC_ACT_EXT_VAL_MASK & gen.Action
|
||||||
}
|
}
|
||||||
|
case nl.TCA_GACT_TM:
|
||||||
|
tcTs := nl.DeserializeTcf(adatum.Value)
|
||||||
|
actionTimestamp = toTimeStamp(tcTs)
|
||||||
}
|
}
|
||||||
case "police":
|
case "police":
|
||||||
parsePolice(adatum, action.(*PoliceAction))
|
parsePolice(adatum, action.(*PoliceAction))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case nl.TCA_ACT_STATS:
|
||||||
|
s, err := parseTcStats2(aattr.Value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
actionnStatistic = (*ActionStatistic)(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
action.Attrs().Statistics = actionnStatistic
|
||||||
|
action.Attrs().Timestamp = actionTimestamp
|
||||||
actions = append(actions, action)
|
actions = append(actions, action)
|
||||||
}
|
}
|
||||||
return actions, nil
|
return actions, nil
|
||||||
|
@@ -7,6 +7,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/vishvananda/netlink/nl"
|
"github.com/vishvananda/netlink/nl"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
@@ -1815,6 +1816,7 @@ func TestFilterFlowerAddDel(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
filters, err := FilterList(link, MakeHandle(0xffff, 0))
|
filters, err := FilterList(link, MakeHandle(0xffff, 0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -1881,6 +1883,14 @@ func TestFilterFlowerAddDel(t *testing.T) {
|
|||||||
t.Fatal("Mirred action isn't TC_ACT_STOLEN")
|
t.Fatal("Mirred action isn't TC_ACT_STOLEN")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mia.Timestamp == nil || mia.Timestamp.Installed == 0 {
|
||||||
|
t.Fatal("Incorrect mirred action timestamp")
|
||||||
|
}
|
||||||
|
|
||||||
|
if mia.Statistics == nil {
|
||||||
|
t.Fatal("Incorrect mirred action stats")
|
||||||
|
}
|
||||||
|
|
||||||
ga, ok := flower.Actions[1].(*GenericAction)
|
ga, ok := flower.Actions[1].(*GenericAction)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatal("Unable to find generic action")
|
t.Fatal("Unable to find generic action")
|
||||||
@@ -1890,6 +1900,14 @@ func TestFilterFlowerAddDel(t *testing.T) {
|
|||||||
t.Fatal("Generic action isn't TC_ACT_GOTO_CHAIN")
|
t.Fatal("Generic action isn't TC_ACT_GOTO_CHAIN")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ga.Timestamp == nil || ga.Timestamp.Installed == 0 {
|
||||||
|
t.Fatal("Incorrect generic action timestamp")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ga.Statistics == nil {
|
||||||
|
t.Fatal("Incorrect generic action stats")
|
||||||
|
}
|
||||||
|
|
||||||
if err := FilterDel(filter); err != nil {
|
if err := FilterDel(filter); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@@ -89,7 +89,11 @@ const (
|
|||||||
TCA_STATS_RATE_EST
|
TCA_STATS_RATE_EST
|
||||||
TCA_STATS_QUEUE
|
TCA_STATS_QUEUE
|
||||||
TCA_STATS_APP
|
TCA_STATS_APP
|
||||||
TCA_STATS_MAX = TCA_STATS_APP
|
TCA_STATS_RATE_EST64
|
||||||
|
TCA_STATS_PAD
|
||||||
|
TCA_STATS_BASIC_HW
|
||||||
|
TCA_STATS_PKT64
|
||||||
|
TCA_STATS_MAX = TCA_STATS_PKT64
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -150,6 +154,18 @@ func (x *TcMsg) Serialize() []byte {
|
|||||||
return (*(*[SizeofTcMsg]byte)(unsafe.Pointer(x)))[:]
|
return (*(*[SizeofTcMsg]byte)(unsafe.Pointer(x)))[:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Tcf struct {
|
||||||
|
Install uint64
|
||||||
|
LastUse uint64
|
||||||
|
Expires uint64
|
||||||
|
FirstUse uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeserializeTcf(b []byte) *Tcf {
|
||||||
|
const size = int(unsafe.Sizeof(Tcf{}))
|
||||||
|
return (*Tcf)(unsafe.Pointer(&b[0:size][0]))
|
||||||
|
}
|
||||||
|
|
||||||
// struct tcamsg {
|
// struct tcamsg {
|
||||||
// unsigned char tca_family;
|
// unsigned char tca_family;
|
||||||
// unsigned char tca__pad1;
|
// unsigned char tca__pad1;
|
||||||
@@ -1106,7 +1122,9 @@ func (x *TcSfqRedStats) Serialize() []byte {
|
|||||||
// struct tc_sfq_qopt v0;
|
// struct tc_sfq_qopt v0;
|
||||||
// unsigned int depth; /* max number of packets per flow */
|
// unsigned int depth; /* max number of packets per flow */
|
||||||
// unsigned int headdrop;
|
// unsigned int headdrop;
|
||||||
|
//
|
||||||
// /* SFQRED parameters */
|
// /* SFQRED parameters */
|
||||||
|
//
|
||||||
// __u32 limit; /* HARD maximal flow queue length (bytes) */
|
// __u32 limit; /* HARD maximal flow queue length (bytes) */
|
||||||
// __u32 qth_min; /* Min average length threshold (bytes) */
|
// __u32 qth_min; /* Min average length threshold (bytes) */
|
||||||
// __u32 qth_max; /* Max average length threshold (bytes) */
|
// __u32 qth_max; /* Max average length threshold (bytes) */
|
||||||
@@ -1115,7 +1133,9 @@ func (x *TcSfqRedStats) Serialize() []byte {
|
|||||||
// unsigned char Scell_log; /* cell size for idle damping */
|
// unsigned char Scell_log; /* cell size for idle damping */
|
||||||
// unsigned char flags;
|
// unsigned char flags;
|
||||||
// __u32 max_P; /* probability, high resolution */
|
// __u32 max_P; /* probability, high resolution */
|
||||||
|
//
|
||||||
// /* SFQRED stats */
|
// /* SFQRED stats */
|
||||||
|
//
|
||||||
// struct tc_sfqred_stats stats;
|
// struct tc_sfqred_stats stats;
|
||||||
// };
|
// };
|
||||||
type TcSfqQoptV1 struct {
|
type TcSfqQoptV1 struct {
|
||||||
|
Reference in New Issue
Block a user