forked from florianl/go-tc
-
Notifications
You must be signed in to change notification settings - Fork 2
/
m_police.go
144 lines (134 loc) · 3.53 KB
/
m_police.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package tc
import (
"fmt"
"github.com/mdlayher/netlink"
)
const (
tcaPoliceUnspec = iota
tcaPoliceTbf
tcaPoliceRate
tcaPolicePeakRate
tcaPoliceAvRate
tcaPoliceResult
tcaPoliceTm
tcaPolicePad
tcaPoliceRate64
tcaPolicePeakRate64
)
// PolicyAction defines the action that is applied by Policy.
type PolicyAction uint32
// Default Policy actions.
// PolicyUnspec - skipped as it is -1
const (
PolicyOk PolicyAction = iota
PolicyReclassify
PolicyShot
PolicyPipe
)
// Police represents policing attributes of various filters and classes
type Police struct {
Tbf *Policy
Rate *RateSpec
PeakRate *RateSpec
AvRate *uint32
Result *uint32
Tm *Tcft
Rate64 *uint64
PeakRate64 *uint64
}
// unmarshalPolice parses the Police-encoded data and stores the result in the value pointed to by info.
func unmarshalPolice(data []byte, info *Police) error {
ad, err := netlink.NewAttributeDecoder(data)
if err != nil {
return err
}
ad.ByteOrder = nativeEndian
for ad.Next() {
switch ad.Type() {
case tcaPoliceTbf:
policy := &Policy{}
if err := unmarshalStruct(ad.Bytes(), policy); err != nil {
return err
}
info.Tbf = policy
case tcaPoliceRate:
rate := &RateSpec{}
if err := unmarshalStruct(ad.Bytes(), rate); err != nil {
return err
}
info.Rate = rate
case tcaPolicePeakRate:
rate := &RateSpec{}
if err := unmarshalStruct(ad.Bytes(), rate); err != nil {
return err
}
info.PeakRate = rate
case tcaPoliceAvRate:
info.AvRate = uint32Ptr(ad.Uint32())
case tcaPoliceResult:
info.Result = uint32Ptr(ad.Uint32())
case tcaPoliceTm:
tm := &Tcft{}
if err := unmarshalStruct(ad.Bytes(), tm); err != nil {
return err
}
info.Tm = tm
case tcaPolicePad:
// padding does not contain data, we just skip it
case tcaPoliceRate64:
info.Rate64 = uint64Ptr(ad.Uint64())
return ErrNotImplemented
case tcaPolicePeakRate64:
info.PeakRate64 = uint64Ptr(ad.Uint64())
return ErrNotImplemented
default:
return fmt.Errorf("UnmarshalPolice()\t%d\n\t%v", ad.Type(), ad.Bytes())
}
}
return nil
}
// marshalPolice returns the binary encoding of Police
func marshalPolice(info *Police) ([]byte, error) {
options := []tcOption{}
if info == nil {
return []byte{}, fmt.Errorf("Police: %w", ErrNoArg)
}
// TODO: improve logic and check combinations
if info.Rate != nil {
data, err := marshalStruct(info.Rate)
if err != nil {
return []byte{}, err
}
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaPoliceRate, Data: data})
}
if info.PeakRate != nil {
data, err := marshalStruct(info.PeakRate)
if err != nil {
return []byte{}, err
}
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaPolicePeakRate, Data: data})
}
if info.Tbf != nil {
data, err := marshalStruct(info.Tbf)
if err != nil {
return []byte{}, err
}
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaPoliceTbf, Data: data})
}
if info.AvRate != nil {
options = append(options, tcOption{Interpretation: vtUint32, Type: tcaPoliceAvRate, Data: uint32Value(info.AvRate)})
}
if info.Result != nil {
options = append(options, tcOption{Interpretation: vtUint32, Type: tcaPoliceResult, Data: uint32Value(info.Result)})
}
if info.Rate64 != nil {
return []byte{}, fmt.Errorf("police: rate64: %w", ErrNotImplemented)
}
if info.PeakRate64 != nil {
return []byte{}, fmt.Errorf("police: peakrate64: %w", ErrNotImplemented)
}
if info.Tm != nil {
return []byte{}, ErrNoArgAlter
}
return marshalAttributes(options)
}