1
2
3
4
19
20 package winkernel
21
22 import (
23 "crypto/sha1"
24 "encoding/json"
25 "fmt"
26
27 "github.com/Microsoft/hcsshim/hcn"
28 "k8s.io/klog/v2"
29
30 "strings"
31 )
32
33 type HostNetworkService interface {
34 getNetworkByName(name string) (*hnsNetworkInfo, error)
35 getAllEndpointsByNetwork(networkName string) (map[string]*endpointInfo, error)
36 getEndpointByID(id string) (*endpointInfo, error)
37 getEndpointByIpAddress(ip string, networkName string) (*endpointInfo, error)
38 getEndpointByName(id string) (*endpointInfo, error)
39 createEndpoint(ep *endpointInfo, networkName string) (*endpointInfo, error)
40 deleteEndpoint(hnsID string) error
41 getLoadBalancer(endpoints []endpointInfo, flags loadBalancerFlags, sourceVip string, vip string, protocol uint16, internalPort uint16, externalPort uint16, previousLoadBalancers map[loadBalancerIdentifier]*loadBalancerInfo) (*loadBalancerInfo, error)
42 getAllLoadBalancers() (map[loadBalancerIdentifier]*loadBalancerInfo, error)
43 deleteLoadBalancer(hnsID string) error
44 }
45
46 type hns struct {
47 hcn HcnService
48 }
49
50 var (
51
52 LoadBalancerFlagsIPv6 hcn.LoadBalancerFlags = 2
53
54 LoadBalancerPortMappingFlagsVipExternalIP hcn.LoadBalancerPortMappingFlags = 16
55 )
56
57 func (hns hns) getNetworkByName(name string) (*hnsNetworkInfo, error) {
58 hnsnetwork, err := hns.hcn.GetNetworkByName(name)
59 if err != nil {
60 klog.ErrorS(err, "Error getting network by name")
61 return nil, err
62 }
63
64 var remoteSubnets []*remoteSubnetInfo
65 for _, policy := range hnsnetwork.Policies {
66 if policy.Type == hcn.RemoteSubnetRoute {
67 policySettings := hcn.RemoteSubnetRoutePolicySetting{}
68 err = json.Unmarshal(policy.Settings, &policySettings)
69 if err != nil {
70 return nil, fmt.Errorf("failed to unmarshal Remote Subnet policy settings")
71 }
72 rs := &remoteSubnetInfo{
73 destinationPrefix: policySettings.DestinationPrefix,
74 isolationID: policySettings.IsolationId,
75 providerAddress: policySettings.ProviderAddress,
76 drMacAddress: policySettings.DistributedRouterMacAddress,
77 }
78 remoteSubnets = append(remoteSubnets, rs)
79 }
80 }
81
82 return &hnsNetworkInfo{
83 id: hnsnetwork.Id,
84 name: hnsnetwork.Name,
85 networkType: string(hnsnetwork.Type),
86 remoteSubnets: remoteSubnets,
87 }, nil
88 }
89
90 func (hns hns) getAllEndpointsByNetwork(networkName string) (map[string]*(endpointInfo), error) {
91 hcnnetwork, err := hns.hcn.GetNetworkByName(networkName)
92 if err != nil {
93 klog.ErrorS(err, "failed to get HNS network by name", "name", networkName)
94 return nil, err
95 }
96 endpoints, err := hns.hcn.ListEndpointsOfNetwork(hcnnetwork.Id)
97 if err != nil {
98 return nil, fmt.Errorf("failed to list endpoints: %w", err)
99 }
100 endpointInfos := make(map[string]*(endpointInfo))
101 for _, ep := range endpoints {
102
103 if len(ep.IpConfigurations) == 0 {
104 klog.V(3).InfoS("No IpConfigurations found in endpoint info of queried endpoints", "endpoint", ep)
105 continue
106 }
107
108
109
110
111 endpointInfos[ep.Id] = &endpointInfo{
112 ip: ep.IpConfigurations[0].IpAddress,
113 isLocal: uint32(ep.Flags&hcn.EndpointFlagsRemoteEndpoint) == 0,
114 macAddress: ep.MacAddress,
115 hnsID: ep.Id,
116 hns: hns,
117
118 ready: true,
119 serving: true,
120 terminating: false,
121 }
122 endpointInfos[ep.IpConfigurations[0].IpAddress] = endpointInfos[ep.Id]
123
124 if len(ep.IpConfigurations) == 1 {
125 continue
126 }
127
128
129
130 endpointDualstack := &endpointInfo{
131 ip: ep.IpConfigurations[1].IpAddress,
132 isLocal: uint32(ep.Flags&hcn.EndpointFlagsRemoteEndpoint) == 0,
133 macAddress: ep.MacAddress,
134 hnsID: ep.Id,
135 hns: hns,
136
137 ready: true,
138 serving: true,
139 terminating: false,
140 }
141 endpointInfos[ep.IpConfigurations[1].IpAddress] = endpointDualstack
142 }
143 klog.V(3).InfoS("Queried endpoints from network", "network", networkName)
144 klog.V(5).InfoS("Queried endpoints details", "network", networkName, "endpointInfos", endpointInfos)
145 return endpointInfos, nil
146 }
147
148 func (hns hns) getEndpointByID(id string) (*endpointInfo, error) {
149 hnsendpoint, err := hns.hcn.GetEndpointByID(id)
150 if err != nil {
151 return nil, err
152 }
153 return &endpointInfo{
154 ip: hnsendpoint.IpConfigurations[0].IpAddress,
155 isLocal: uint32(hnsendpoint.Flags&hcn.EndpointFlagsRemoteEndpoint) == 0,
156 macAddress: hnsendpoint.MacAddress,
157 hnsID: hnsendpoint.Id,
158 hns: hns,
159 }, nil
160 }
161 func (hns hns) getEndpointByIpAddress(ip string, networkName string) (*endpointInfo, error) {
162 hnsnetwork, err := hns.hcn.GetNetworkByName(networkName)
163 if err != nil {
164 klog.ErrorS(err, "Error getting network by name")
165 return nil, err
166 }
167
168 endpoints, err := hns.hcn.ListEndpoints()
169 if err != nil {
170 return nil, fmt.Errorf("failed to list endpoints: %w", err)
171 }
172 for _, endpoint := range endpoints {
173 equal := false
174 if endpoint.IpConfigurations != nil && len(endpoint.IpConfigurations) > 0 {
175 equal = endpoint.IpConfigurations[0].IpAddress == ip
176
177 if !equal && len(endpoint.IpConfigurations) > 1 {
178 equal = endpoint.IpConfigurations[1].IpAddress == ip
179 }
180 }
181 if equal && strings.EqualFold(endpoint.HostComputeNetwork, hnsnetwork.Id) {
182 return &endpointInfo{
183 ip: ip,
184 isLocal: uint32(endpoint.Flags&hcn.EndpointFlagsRemoteEndpoint) == 0,
185 macAddress: endpoint.MacAddress,
186 hnsID: endpoint.Id,
187 hns: hns,
188 }, nil
189 }
190 }
191 return nil, fmt.Errorf("Endpoint %v not found on network %s", ip, networkName)
192 }
193 func (hns hns) getEndpointByName(name string) (*endpointInfo, error) {
194 hnsendpoint, err := hns.hcn.GetEndpointByName(name)
195 if err != nil {
196 return nil, err
197 }
198 return &endpointInfo{
199 ip: hnsendpoint.IpConfigurations[0].IpAddress,
200 isLocal: uint32(hnsendpoint.Flags&hcn.EndpointFlagsRemoteEndpoint) == 0,
201 macAddress: hnsendpoint.MacAddress,
202 hnsID: hnsendpoint.Id,
203 hns: hns,
204 }, nil
205 }
206 func (hns hns) createEndpoint(ep *endpointInfo, networkName string) (*endpointInfo, error) {
207 hnsNetwork, err := hns.hcn.GetNetworkByName(networkName)
208 if err != nil {
209 return nil, err
210 }
211 var flags hcn.EndpointFlags
212 if !ep.isLocal {
213 flags |= hcn.EndpointFlagsRemoteEndpoint
214 }
215 ipConfig := &hcn.IpConfig{
216 IpAddress: ep.ip,
217 }
218 hnsEndpoint := &hcn.HostComputeEndpoint{
219 IpConfigurations: []hcn.IpConfig{*ipConfig},
220 MacAddress: ep.macAddress,
221 Flags: flags,
222 SchemaVersion: hcn.SchemaVersion{
223 Major: 2,
224 Minor: 0,
225 },
226 }
227
228 var createdEndpoint *hcn.HostComputeEndpoint
229 if !ep.isLocal {
230 if len(ep.providerAddress) != 0 {
231 policySettings := hcn.ProviderAddressEndpointPolicySetting{
232 ProviderAddress: ep.providerAddress,
233 }
234 policySettingsJson, err := json.Marshal(policySettings)
235 if err != nil {
236 return nil, fmt.Errorf("PA Policy creation failed: %v", err)
237 }
238 paPolicy := hcn.EndpointPolicy{
239 Type: hcn.NetworkProviderAddress,
240 Settings: policySettingsJson,
241 }
242 hnsEndpoint.Policies = append(hnsEndpoint.Policies, paPolicy)
243 }
244 createdEndpoint, err = hns.hcn.CreateRemoteEndpoint(hnsNetwork, hnsEndpoint)
245 if err != nil {
246 return nil, err
247 }
248 } else {
249 createdEndpoint, err = hns.hcn.CreateEndpoint(hnsNetwork, hnsEndpoint)
250 if err != nil {
251 return nil, err
252 }
253 }
254 return &endpointInfo{
255 ip: createdEndpoint.IpConfigurations[0].IpAddress,
256 isLocal: uint32(createdEndpoint.Flags&hcn.EndpointFlagsRemoteEndpoint) == 0,
257 macAddress: createdEndpoint.MacAddress,
258 hnsID: createdEndpoint.Id,
259 providerAddress: ep.providerAddress,
260 hns: hns,
261 }, nil
262 }
263 func (hns hns) deleteEndpoint(hnsID string) error {
264 hnsendpoint, err := hns.hcn.GetEndpointByID(hnsID)
265 if err != nil {
266 return err
267 }
268 err = hns.hcn.DeleteEndpoint(hnsendpoint)
269 if err == nil {
270 klog.V(3).InfoS("Remote endpoint resource deleted", "hnsID", hnsID)
271 }
272 return err
273 }
274
275
276 func findLoadBalancerID(endpoints []endpointInfo, vip string, protocol, internalPort, externalPort uint16) (loadBalancerIdentifier, error) {
277
278 hash, err := hashEndpoints(endpoints)
279 if err != nil {
280 klog.V(2).ErrorS(err, "Error hashing endpoints", "endpoints", endpoints)
281 return loadBalancerIdentifier{}, err
282 }
283 if len(vip) > 0 {
284 return loadBalancerIdentifier{protocol: protocol, internalPort: internalPort, externalPort: externalPort, vip: vip, endpointsHash: hash}, nil
285 }
286 return loadBalancerIdentifier{protocol: protocol, internalPort: internalPort, externalPort: externalPort, endpointsHash: hash}, nil
287 }
288
289 func (hns hns) getAllLoadBalancers() (map[loadBalancerIdentifier]*loadBalancerInfo, error) {
290 lbs, err := hns.hcn.ListLoadBalancers()
291 var id loadBalancerIdentifier
292 if err != nil {
293 return nil, err
294 }
295 loadBalancers := make(map[loadBalancerIdentifier]*(loadBalancerInfo))
296 for _, lb := range lbs {
297 portMap := lb.PortMappings[0]
298
299 hash, err := hashEndpoints(lb.HostComputeEndpoints)
300 if err != nil {
301 klog.V(2).ErrorS(err, "Error hashing endpoints", "policy", lb)
302 return nil, err
303 }
304 if len(lb.FrontendVIPs) == 0 {
305
306 id = loadBalancerIdentifier{protocol: uint16(portMap.Protocol), internalPort: portMap.InternalPort, externalPort: portMap.ExternalPort, endpointsHash: hash}
307 } else {
308 id = loadBalancerIdentifier{protocol: uint16(portMap.Protocol), internalPort: portMap.InternalPort, externalPort: portMap.ExternalPort, vip: lb.FrontendVIPs[0], endpointsHash: hash}
309 }
310 loadBalancers[id] = &loadBalancerInfo{
311 hnsID: lb.Id,
312 }
313 }
314 klog.V(3).InfoS("Queried load balancers", "count", len(lbs))
315 return loadBalancers, nil
316 }
317
318 func (hns hns) getLoadBalancer(endpoints []endpointInfo, flags loadBalancerFlags, sourceVip string, vip string, protocol uint16, internalPort uint16, externalPort uint16, previousLoadBalancers map[loadBalancerIdentifier]*loadBalancerInfo) (*loadBalancerInfo, error) {
319 var id loadBalancerIdentifier
320 vips := []string{}
321
322 hash, err := hashEndpoints(endpoints)
323 if err != nil {
324 klog.V(2).ErrorS(err, "Error hashing endpoints", "endpoints", endpoints)
325 return nil, err
326 }
327 if len(vip) > 0 {
328 id = loadBalancerIdentifier{protocol: protocol, internalPort: internalPort, externalPort: externalPort, vip: vip, endpointsHash: hash}
329 vips = append(vips, vip)
330 } else {
331 id = loadBalancerIdentifier{protocol: protocol, internalPort: internalPort, externalPort: externalPort, endpointsHash: hash}
332 }
333
334 if lb, found := previousLoadBalancers[id]; found {
335 klog.V(1).InfoS("Found cached Hns loadbalancer policy resource", "policies", lb)
336 return lb, nil
337 }
338
339 lbPortMappingFlags := hcn.LoadBalancerPortMappingFlagsNone
340 if flags.isILB {
341 lbPortMappingFlags |= hcn.LoadBalancerPortMappingFlagsILB
342 }
343 if flags.useMUX {
344 lbPortMappingFlags |= hcn.LoadBalancerPortMappingFlagsUseMux
345 }
346 if flags.preserveDIP {
347 lbPortMappingFlags |= hcn.LoadBalancerPortMappingFlagsPreserveDIP
348 }
349 if flags.localRoutedVIP {
350 lbPortMappingFlags |= hcn.LoadBalancerPortMappingFlagsLocalRoutedVIP
351 }
352 if flags.isVipExternalIP {
353 lbPortMappingFlags |= LoadBalancerPortMappingFlagsVipExternalIP
354 }
355
356 lbFlags := hcn.LoadBalancerFlagsNone
357 if flags.isDSR {
358 lbFlags |= hcn.LoadBalancerFlagsDSR
359 }
360
361 if flags.isIPv6 {
362 lbFlags |= LoadBalancerFlagsIPv6
363 }
364
365 lbDistributionType := hcn.LoadBalancerDistributionNone
366
367 if flags.sessionAffinity {
368 lbDistributionType = hcn.LoadBalancerDistributionSourceIP
369 }
370
371 loadBalancer := &hcn.HostComputeLoadBalancer{
372 SourceVIP: sourceVip,
373 PortMappings: []hcn.LoadBalancerPortMapping{
374 {
375 Protocol: uint32(protocol),
376 InternalPort: internalPort,
377 ExternalPort: externalPort,
378 DistributionType: lbDistributionType,
379 Flags: lbPortMappingFlags,
380 },
381 },
382 FrontendVIPs: vips,
383 SchemaVersion: hcn.SchemaVersion{
384 Major: 2,
385 Minor: 0,
386 },
387 Flags: lbFlags,
388 }
389
390 for _, ep := range endpoints {
391 loadBalancer.HostComputeEndpoints = append(loadBalancer.HostComputeEndpoints, ep.hnsID)
392 }
393
394 lb, err := hns.hcn.CreateLoadBalancer(loadBalancer)
395
396 if err != nil {
397 return nil, err
398 }
399
400 klog.V(1).InfoS("Created Hns loadbalancer policy resource", "loadBalancer", lb)
401 lbInfo := &loadBalancerInfo{
402 hnsID: lb.Id,
403 }
404
405 previousLoadBalancers[id] = lbInfo
406 return lbInfo, err
407 }
408
409 func (hns hns) deleteLoadBalancer(hnsID string) error {
410 lb, err := hns.hcn.GetLoadBalancerByID(hnsID)
411 if err != nil {
412
413 return nil
414 }
415
416 err = hns.hcn.DeleteLoadBalancer(lb)
417 if err != nil {
418
419
420 klog.V(1).ErrorS(err, "Error deleting Hns loadbalancer policy resource. Attempting one more time...", "loadBalancer", lb)
421 return hns.hcn.DeleteLoadBalancer(lb)
422 }
423 return err
424 }
425
426
427 func hashEndpoints[T string | endpointInfo](endpoints []T) (hash [20]byte, err error) {
428 var id string
429
430 defer func() {
431 if r := recover(); r != nil {
432 err = r.(error)
433 hash = [20]byte{}
434 }
435 }()
436
437
438 for _, ep := range endpoints {
439 switch x := any(ep).(type) {
440 case endpointInfo:
441 id = strings.ToUpper(x.hnsID)
442 case string:
443 id = x
444 }
445 if len(id) > 0 {
446
447
448 hash = xor(hash, sha1.Sum(([]byte(id))))
449 }
450 }
451 return
452 }
453
454 func xor(b1 [20]byte, b2 [20]byte) (xorbytes [20]byte) {
455 for i := 0; i < 20; i++ {
456 xorbytes[i] = b1[i] ^ b2[i]
457 }
458 return xorbytes
459 }
460
View as plain text