1package netlink
2
3import (
4	"fmt"
5	"math"
6)
7
8const (
9	HANDLE_NONE      = 0
10	HANDLE_INGRESS   = 0xFFFFFFF1
11	HANDLE_CLSACT    = HANDLE_INGRESS
12	HANDLE_ROOT      = 0xFFFFFFFF
13	PRIORITY_MAP_LEN = 16
14)
15const (
16	HANDLE_MIN_INGRESS = 0xFFFFFFF2
17	HANDLE_MIN_EGRESS  = 0xFFFFFFF3
18)
19
20type Qdisc interface {
21	Attrs() *QdiscAttrs
22	Type() string
23}
24
25// QdiscAttrs represents a netlink qdisc. A qdisc is associated with a link,
26// has a handle, a parent and a refcnt. The root qdisc of a device should
27// have parent == HANDLE_ROOT.
28type QdiscAttrs struct {
29	LinkIndex int
30	Handle    uint32
31	Parent    uint32
32	Refcnt    uint32 // read only
33}
34
35func (q QdiscAttrs) String() string {
36	return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Refcnt: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Refcnt)
37}
38
39func MakeHandle(major, minor uint16) uint32 {
40	return (uint32(major) << 16) | uint32(minor)
41}
42
43func MajorMinor(handle uint32) (uint16, uint16) {
44	return uint16((handle & 0xFFFF0000) >> 16), uint16(handle & 0x0000FFFFF)
45}
46
47func HandleStr(handle uint32) string {
48	switch handle {
49	case HANDLE_NONE:
50		return "none"
51	case HANDLE_INGRESS:
52		return "ingress"
53	case HANDLE_ROOT:
54		return "root"
55	default:
56		major, minor := MajorMinor(handle)
57		return fmt.Sprintf("%x:%x", major, minor)
58	}
59}
60
61func Percentage2u32(percentage float32) uint32 {
62	// FIXME this is most likely not the best way to convert from % to uint32
63	if percentage == 100 {
64		return math.MaxUint32
65	}
66	return uint32(math.MaxUint32 * (percentage / 100))
67}
68
69// PfifoFast is the default qdisc created by the kernel if one has not
70// been defined for the interface
71type PfifoFast struct {
72	QdiscAttrs
73	Bands       uint8
74	PriorityMap [PRIORITY_MAP_LEN]uint8
75}
76
77func (qdisc *PfifoFast) Attrs() *QdiscAttrs {
78	return &qdisc.QdiscAttrs
79}
80
81func (qdisc *PfifoFast) Type() string {
82	return "pfifo_fast"
83}
84
85// Prio is a basic qdisc that works just like PfifoFast
86type Prio struct {
87	QdiscAttrs
88	Bands       uint8
89	PriorityMap [PRIORITY_MAP_LEN]uint8
90}
91
92func NewPrio(attrs QdiscAttrs) *Prio {
93	return &Prio{
94		QdiscAttrs:  attrs,
95		Bands:       3,
96		PriorityMap: [PRIORITY_MAP_LEN]uint8{1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
97	}
98}
99
100func (qdisc *Prio) Attrs() *QdiscAttrs {
101	return &qdisc.QdiscAttrs
102}
103
104func (qdisc *Prio) Type() string {
105	return "prio"
106}
107
108// Htb is a classful qdisc that rate limits based on tokens
109type Htb struct {
110	QdiscAttrs
111	Version      uint32
112	Rate2Quantum uint32
113	Defcls       uint32
114	Debug        uint32
115	DirectPkts   uint32
116}
117
118func NewHtb(attrs QdiscAttrs) *Htb {
119	return &Htb{
120		QdiscAttrs:   attrs,
121		Version:      3,
122		Defcls:       0,
123		Rate2Quantum: 10,
124		Debug:        0,
125		DirectPkts:   0,
126	}
127}
128
129func (qdisc *Htb) Attrs() *QdiscAttrs {
130	return &qdisc.QdiscAttrs
131}
132
133func (qdisc *Htb) Type() string {
134	return "htb"
135}
136
137// Netem is a classless qdisc that rate limits based on tokens
138
139type NetemQdiscAttrs struct {
140	Latency       uint32  // in us
141	DelayCorr     float32 // in %
142	Limit         uint32
143	Loss          float32 // in %
144	LossCorr      float32 // in %
145	Gap           uint32
146	Duplicate     float32 // in %
147	DuplicateCorr float32 // in %
148	Jitter        uint32  // in us
149	ReorderProb   float32 // in %
150	ReorderCorr   float32 // in %
151	CorruptProb   float32 // in %
152	CorruptCorr   float32 // in %
153}
154
155func (q NetemQdiscAttrs) String() string {
156	return fmt.Sprintf(
157		"{Latency: %d, Limit: %d, Loss: %f, Gap: %d, Duplicate: %f, Jitter: %d}",
158		q.Latency, q.Limit, q.Loss, q.Gap, q.Duplicate, q.Jitter,
159	)
160}
161
162type Netem struct {
163	QdiscAttrs
164	Latency       uint32
165	DelayCorr     uint32
166	Limit         uint32
167	Loss          uint32
168	LossCorr      uint32
169	Gap           uint32
170	Duplicate     uint32
171	DuplicateCorr uint32
172	Jitter        uint32
173	ReorderProb   uint32
174	ReorderCorr   uint32
175	CorruptProb   uint32
176	CorruptCorr   uint32
177}
178
179func (qdisc *Netem) Attrs() *QdiscAttrs {
180	return &qdisc.QdiscAttrs
181}
182
183func (qdisc *Netem) Type() string {
184	return "netem"
185}
186
187// Tbf is a classless qdisc that rate limits based on tokens
188type Tbf struct {
189	QdiscAttrs
190	Rate     uint64
191	Limit    uint32
192	Buffer   uint32
193	Peakrate uint64
194	Minburst uint32
195	// TODO: handle other settings
196}
197
198func (qdisc *Tbf) Attrs() *QdiscAttrs {
199	return &qdisc.QdiscAttrs
200}
201
202func (qdisc *Tbf) Type() string {
203	return "tbf"
204}
205
206// Ingress is a qdisc for adding ingress filters
207type Ingress struct {
208	QdiscAttrs
209}
210
211func (qdisc *Ingress) Attrs() *QdiscAttrs {
212	return &qdisc.QdiscAttrs
213}
214
215func (qdisc *Ingress) Type() string {
216	return "ingress"
217}
218
219// GenericQdisc qdiscs represent types that are not currently understood
220// by this netlink library.
221type GenericQdisc struct {
222	QdiscAttrs
223	QdiscType string
224}
225
226func (qdisc *GenericQdisc) Attrs() *QdiscAttrs {
227	return &qdisc.QdiscAttrs
228}
229
230func (qdisc *GenericQdisc) Type() string {
231	return qdisc.QdiscType
232}
233