1
16
17 package topologymanager
18
19 import (
20 "fmt"
21 "time"
22
23 cadvisorapi "github.com/google/cadvisor/info/v1"
24 v1 "k8s.io/api/core/v1"
25 "k8s.io/klog/v2"
26 "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask"
27 "k8s.io/kubernetes/pkg/kubelet/lifecycle"
28 "k8s.io/kubernetes/pkg/kubelet/metrics"
29 )
30
31 const (
32
33
34
35
36
37
38
39
40 maxAllowableNUMANodes = 8
41
42 ErrorTopologyAffinity = "TopologyAffinityError"
43 )
44
45
46 type TopologyAffinityError struct{}
47
48 func (e TopologyAffinityError) Error() string {
49 return "Resources cannot be allocated with Topology locality"
50 }
51
52 func (e TopologyAffinityError) Type() string {
53 return ErrorTopologyAffinity
54 }
55
56
57 type Manager interface {
58
59 lifecycle.PodAdmitHandler
60
61
62 AddHintProvider(HintProvider)
63
64 AddContainer(pod *v1.Pod, container *v1.Container, containerID string)
65
66 RemoveContainer(containerID string) error
67
68 Store
69 }
70
71 type manager struct {
72
73 scope Scope
74 }
75
76
77
78
79 type HintProvider interface {
80
81
82
83
84
85
86
87 GetTopologyHints(pod *v1.Pod, container *v1.Container) map[string][]TopologyHint
88
89
90 GetPodTopologyHints(pod *v1.Pod) map[string][]TopologyHint
91
92
93
94 Allocate(pod *v1.Pod, container *v1.Container) error
95 }
96
97
98 type Store interface {
99 GetAffinity(podUID string, containerName string) TopologyHint
100 GetPolicy() Policy
101 }
102
103
104 type TopologyHint struct {
105 NUMANodeAffinity bitmask.BitMask
106
107
108 Preferred bool
109 }
110
111
112 func (th *TopologyHint) IsEqual(topologyHint TopologyHint) bool {
113 if th.Preferred == topologyHint.Preferred {
114 if th.NUMANodeAffinity == nil || topologyHint.NUMANodeAffinity == nil {
115 return th.NUMANodeAffinity == topologyHint.NUMANodeAffinity
116 }
117 return th.NUMANodeAffinity.IsEqual(topologyHint.NUMANodeAffinity)
118 }
119 return false
120 }
121
122
123
124
125 func (th *TopologyHint) LessThan(other TopologyHint) bool {
126 if th.Preferred != other.Preferred {
127 return th.Preferred
128 }
129 return th.NUMANodeAffinity.IsNarrowerThan(other.NUMANodeAffinity)
130 }
131
132 var _ Manager = &manager{}
133
134
135 func NewManager(topology []cadvisorapi.Node, topologyPolicyName string, topologyScopeName string, topologyPolicyOptions map[string]string) (Manager, error) {
136
137 if topologyPolicyName == PolicyNone {
138 klog.InfoS("Creating topology manager with none policy")
139 return &manager{scope: NewNoneScope()}, nil
140 }
141
142 opts, err := NewPolicyOptions(topologyPolicyOptions)
143 if err != nil {
144 return nil, err
145 }
146
147 klog.InfoS("Creating topology manager with policy per scope", "topologyPolicyName", topologyPolicyName, "topologyScopeName", topologyScopeName, "topologyPolicyOptions", opts)
148
149 numaInfo, err := NewNUMAInfo(topology, opts)
150 if err != nil {
151 return nil, fmt.Errorf("cannot discover NUMA topology: %w", err)
152 }
153
154 if topologyPolicyName != PolicyNone && len(numaInfo.Nodes) > maxAllowableNUMANodes {
155 return nil, fmt.Errorf("unsupported on machines with more than %v NUMA Nodes", maxAllowableNUMANodes)
156 }
157
158 var policy Policy
159 switch topologyPolicyName {
160
161 case PolicyBestEffort:
162 policy = NewBestEffortPolicy(numaInfo, opts)
163
164 case PolicyRestricted:
165 policy = NewRestrictedPolicy(numaInfo, opts)
166
167 case PolicySingleNumaNode:
168 policy = NewSingleNumaNodePolicy(numaInfo, opts)
169
170 default:
171 return nil, fmt.Errorf("unknown policy: \"%s\"", topologyPolicyName)
172 }
173
174 var scope Scope
175 switch topologyScopeName {
176
177 case containerTopologyScope:
178 scope = NewContainerScope(policy)
179
180 case podTopologyScope:
181 scope = NewPodScope(policy)
182
183 default:
184 return nil, fmt.Errorf("unknown scope: \"%s\"", topologyScopeName)
185 }
186
187 manager := &manager{
188 scope: scope,
189 }
190
191 return manager, nil
192 }
193
194 func (m *manager) GetAffinity(podUID string, containerName string) TopologyHint {
195 return m.scope.GetAffinity(podUID, containerName)
196 }
197
198 func (m *manager) GetPolicy() Policy {
199 return m.scope.GetPolicy()
200 }
201
202 func (m *manager) AddHintProvider(h HintProvider) {
203 m.scope.AddHintProvider(h)
204 }
205
206 func (m *manager) AddContainer(pod *v1.Pod, container *v1.Container, containerID string) {
207 m.scope.AddContainer(pod, container, containerID)
208 }
209
210 func (m *manager) RemoveContainer(containerID string) error {
211 return m.scope.RemoveContainer(containerID)
212 }
213
214 func (m *manager) Admit(attrs *lifecycle.PodAdmitAttributes) lifecycle.PodAdmitResult {
215 klog.InfoS("Topology Admit Handler", "podUID", attrs.Pod.UID, "podNamespace", attrs.Pod.Namespace, "podName", attrs.Pod.Name)
216 metrics.TopologyManagerAdmissionRequestsTotal.Inc()
217
218 startTime := time.Now()
219 podAdmitResult := m.scope.Admit(attrs.Pod)
220 metrics.TopologyManagerAdmissionDuration.Observe(float64(time.Since(startTime).Milliseconds()))
221
222 return podAdmitResult
223 }
224
View as plain text