enable rule statistic and time statistic for flower actions

This commit is contained in:
liuhao.0912
2023-07-27 14:37:55 +08:00
committed by Alessandro Boch
parent 004274e828
commit 0ced838538
6 changed files with 128 additions and 28 deletions

View File

@@ -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{},
} }
} }

View File

@@ -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))
}
} }
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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)
} }

View File

@@ -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 {