-
Notifications
You must be signed in to change notification settings - Fork 2.8k
/
ops.go
137 lines (120 loc) · 3.79 KB
/
ops.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
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium
package bandwidth
import (
"context"
"fmt"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
"github.com/cilium/cilium/pkg/datapath/tables"
"github.com/cilium/cilium/pkg/datapath/types"
"github.com/cilium/cilium/pkg/statedb"
"github.com/cilium/cilium/pkg/statedb/reconciler"
)
type ops struct {
log logrus.FieldLogger
isEnabled func() bool
}
func newOps(log logrus.FieldLogger, mgr types.BandwidthManager) reconciler.Operations[*tables.BandwidthQDisc] {
return &ops{log, mgr.Enabled}
}
// Delete implements reconciler.Operations.
func (*ops) Delete(context.Context, statedb.ReadTxn, *tables.BandwidthQDisc) error {
// We don't restore the original qdisc on delete.
return nil
}
// Prune implements reconciler.Operations.
func (*ops) Prune(context.Context, statedb.ReadTxn, statedb.Iterator[*tables.BandwidthQDisc]) error {
// We don't touch qdiscs of other devices.
return nil
}
// Update implements reconciler.Operations.
func (ops *ops) Update(ctx context.Context, txn statedb.ReadTxn, q *tables.BandwidthQDisc, changed *bool) error {
if !ops.isEnabled() {
// Probe results show that the system doesn't support BandwidthManager, so
// bail out.
return nil
}
link, err := netlink.LinkByIndex(q.LinkIndex)
if err != nil {
return fmt.Errorf("LinkByIndex: %w", err)
}
device := link.Attrs().Name
// Check if the qdiscs are already set up as expected.
qdiscs, err := netlink.QdiscList(link)
if err != nil {
return fmt.Errorf("QdiscList: %w", err)
}
if len(qdiscs) > 0 {
ok := qdiscs[0].Type() == "mq"
if qdiscs[0].Type() == "fq" {
fq, _ := qdiscs[0].(*netlink.Fq)
// If it's "fq" and with our parameters, then assume this was
// already set up and there wasn't any MQ support.
ok = fq.Horizon == uint32(q.FqHorizon.Microseconds()) &&
fq.Buckets == q.FqBuckets
}
if ok {
return nil
}
}
if changed != nil {
*changed = true
}
// We strictly want to avoid a down/up cycle on the device at
// runtime, so given we've changed the default qdisc to FQ, we
// need to reset the root qdisc, and then set up MQ which will
// automatically get FQ leaf qdiscs (given it's been default).
qdisc := &netlink.GenericQdisc{
QdiscAttrs: netlink.QdiscAttrs{
LinkIndex: link.Attrs().Index,
Parent: netlink.HANDLE_ROOT,
},
QdiscType: "noqueue",
}
if err := netlink.QdiscReplace(qdisc); err != nil {
return fmt.Errorf("cannot replace root Qdisc to %s on device %s: %w", qdisc.QdiscType, device, err)
}
qdisc = &netlink.GenericQdisc{
QdiscAttrs: netlink.QdiscAttrs{
LinkIndex: link.Attrs().Index,
Parent: netlink.HANDLE_ROOT,
},
QdiscType: "mq",
}
which := "mq with fq leaves"
if err := netlink.QdiscReplace(qdisc); err != nil {
// No MQ support, so just replace to FQ directly.
fq := &netlink.Fq{
QdiscAttrs: netlink.QdiscAttrs{
LinkIndex: link.Attrs().Index,
Parent: netlink.HANDLE_ROOT,
},
Pacing: 1,
}
// At this point there is nothing we can do about
// it if we fail here, so hard bail out.
if err = netlink.QdiscReplace(fq); err != nil {
return fmt.Errorf("cannot replace root Qdisc to %s on device %s: %w", fq.Type(), device, err)
}
which = "fq"
}
ops.log.WithField("device", device).Infof("Setting qdisc to %s", which)
// Set the fq parameters
qdiscs, err = netlink.QdiscList(link)
if err != nil {
return fmt.Errorf("QdiscList: %w", err)
}
for _, qdisc := range qdiscs {
if qdisc.Type() == "fq" {
fq, _ := qdisc.(*netlink.Fq)
fq.Horizon = uint32(FqDefaultHorizon.Microseconds())
fq.Buckets = uint32(FqDefaultBuckets)
if err := netlink.QdiscReplace(qdisc); err != nil {
return fmt.Errorf("cannot set qdisc attributes: %w", err)
}
}
}
return nil
}
var _ reconciler.Operations[*tables.BandwidthQDisc] = &ops{}