github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/maps/lbmap/types.go (about) 1 // Copyright 2019 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package lbmap 16 17 import ( 18 "fmt" 19 "net" 20 "unsafe" 21 22 "github.com/cilium/cilium/pkg/bpf" 23 "github.com/cilium/cilium/pkg/loadbalancer" 24 "github.com/cilium/cilium/pkg/logging/logfields" 25 "github.com/cilium/cilium/pkg/u8proto" 26 27 "github.com/sirupsen/logrus" 28 ) 29 30 // BackendAddrID is the type of a service endpoint's unique identifier which 31 // consists of "IP:PORT" 32 type BackendAddrID string 33 34 // ServiceKey is the interface describing protocol independent key for services map. 35 type ServiceKey interface { 36 bpf.MapKey 37 38 // Returns true if the key is of type IPv6 39 IsIPv6() bool 40 41 // Returns the BPF map matching the key type 42 Map() *bpf.Map 43 44 // Returns the BPF Weighted Round Robin map matching the key type 45 RRMap() *bpf.Map 46 47 // Returns a RevNatValue matching a ServiceKey 48 RevNatValue() RevNatValue 49 50 // Returns the port set in the key or 0 51 GetPort() uint16 52 53 // Set the backend index (master: 0, backend: nth backend) 54 SetBackend(int) 55 56 // Return backend index 57 GetBackend() int 58 59 // ToNetwork converts fields to network byte order. 60 ToNetwork() ServiceKey 61 62 // ToHost converts fields to host byte order. 63 ToHost() ServiceKey 64 } 65 66 // ServiceValue is the interface describing protocol independent value for services map. 67 type ServiceValue interface { 68 bpf.MapValue 69 70 // Returns a RevNatKey matching a ServiceValue 71 RevNatKey() RevNatKey 72 73 // Set the number of backends 74 SetCount(int) 75 76 // Get the number of backends 77 GetCount() int 78 79 // Set address to map to (left blank for master) 80 SetAddress(net.IP) error 81 82 // Get address to map to (left blank for master) 83 GetAddress() net.IP 84 85 // Set port to map to (left blank for master) 86 SetPort(uint16) 87 88 // Get the port number 89 GetPort() uint16 90 91 // Set reverse NAT identifier 92 SetRevNat(int) 93 94 // Set Weight 95 SetWeight(uint16) 96 97 // Get Weight 98 GetWeight() uint16 99 100 // ToNetwork converts fields to network byte order. 101 ToNetwork() ServiceValue 102 103 // ToHost converts fields to host byte order. 104 ToHost() ServiceValue 105 106 // Get BackendAddrID of the service value 107 BackendAddrID() BackendAddrID 108 109 // Returns true if the value is of type IPv6 110 IsIPv6() bool 111 } 112 113 // ServiceKey is the interface describing protocol independent key for services map v2. 114 // 115 // NOTE: ServiceKeyV2.String() output should match output of corresponding ServiceKey.String()! 116 type ServiceKeyV2 interface { 117 bpf.MapKey 118 119 // Return true if the key is of type IPv6 120 IsIPv6() bool 121 122 // Return the BPF map matching the key type 123 Map() *bpf.Map 124 125 // Return the BPF Weighted Round Robin map matching the key type 126 RRMap() *bpf.Map 127 128 // Set slave slot for the key 129 SetSlave(slave int) 130 131 // Get slave slot of the key 132 GetSlave() int 133 134 // Get frontend IP address 135 GetAddress() net.IP 136 137 // Get frontend port 138 GetPort() uint16 139 140 // Delete entry identified with the key from the matching map 141 MapDelete() error 142 143 // ToNetwork converts fields to network byte order. 144 ToNetwork() ServiceKeyV2 145 } 146 147 // ServiceValue is the interface describing protocol independent value for services map v2. 148 type ServiceValueV2 interface { 149 bpf.MapValue 150 151 // Set the number of backends 152 SetCount(int) 153 154 // Get the number of backends 155 GetCount() int 156 157 // Set reverse NAT identifier 158 SetRevNat(int) 159 160 // Get reverse NAT identifier 161 GetRevNat() int 162 163 // Set weight 164 SetWeight(uint16) 165 166 // Get weight 167 GetWeight() uint16 168 169 // Set backend identifier 170 SetBackendID(id loadbalancer.BackendID) 171 172 // Get backend identifier 173 GetBackendID() loadbalancer.BackendID 174 175 // Returns a RevNatKey matching a ServiceValue 176 RevNatKey() RevNatKey 177 178 // Convert fields to network byte order. 179 ToNetwork() ServiceValueV2 180 } 181 182 // BackendKey is the interface describing protocol independent backend key. 183 type BackendKey interface { 184 bpf.MapKey 185 186 // Return the BPF map matching the type 187 Map() *bpf.Map 188 189 // Set backend identifier 190 SetID(loadbalancer.BackendID) 191 192 // Get backend identifier 193 GetID() loadbalancer.BackendID 194 } 195 196 // BackendValue is the interface describing protocol independent backend value. 197 type BackendValue interface { 198 bpf.MapValue 199 200 // Get backend address 201 GetAddress() net.IP 202 203 // Get backend port 204 GetPort() uint16 205 206 // Get backend address identifier (string of IP:Port) 207 BackendAddrID() BackendAddrID 208 209 // Convert fields to network byte order. 210 ToNetwork() BackendValue 211 } 212 213 // Backend is the interface describing protocol independent backend used by services v2. 214 type Backend interface { 215 // Return true if the value is of type IPv6 216 IsIPv6() bool 217 218 // Return the BPF map matching the type 219 Map() *bpf.Map 220 221 // Get backend identifier 222 GetID() loadbalancer.BackendID 223 224 // Get key of the backend entry 225 GetKey() BackendKey 226 227 // Get value of the backend entry 228 GetValue() BackendValue 229 } 230 231 type RevNatKey interface { 232 bpf.MapKey 233 234 // Returns true if the key is of type IPv6 235 IsIPv6() bool 236 237 // Returns the BPF map matching the key type 238 Map() *bpf.Map 239 240 // ToNetwork converts fields to network byte order. 241 ToNetwork() RevNatKey 242 243 // Returns the key value 244 GetKey() uint16 245 } 246 247 type RevNatValue interface { 248 bpf.MapValue 249 250 // ToNetwork converts fields to network byte order. 251 ToNetwork() RevNatValue 252 } 253 254 type idx [MaxSeq]uint16 255 256 // DeepCopyInto is a deepcopy function, copying the receiver, writing into out. in must be non-nil. 257 func (in *idx) DeepCopyInto(out *idx) { 258 copy(out[:], in[:]) 259 return 260 } 261 262 // +k8s:deepcopy-gen=true 263 // +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapValue 264 type RRSeqValue struct { 265 // Length of Generated sequence 266 Count uint16 267 268 // Generated Sequence 269 Idx idx 270 } 271 272 func (s *RRSeqValue) GetValuePtr() unsafe.Pointer { return unsafe.Pointer(s) } 273 274 func (s *RRSeqValue) String() string { 275 return fmt.Sprintf("count=%d idx=%v", s.Count, s.Idx) 276 } 277 278 // l3n4Addr2ServiceKey converts the given l3n4Addr to a ServiceKey with the slave ID 279 // set to 0. 280 func l3n4Addr2ServiceKey(l3n4Addr loadbalancer.L3n4AddrID) ServiceKey { 281 log.WithField(logfields.L3n4AddrID, l3n4Addr).Debug("converting L3n4Addr to ServiceKey") 282 if l3n4Addr.IsIPv6() { 283 return NewService6Key(l3n4Addr.IP, l3n4Addr.Port, 0) 284 } 285 return NewService4Key(l3n4Addr.IP, l3n4Addr.Port, 0) 286 } 287 288 // LBSVC2ServiceKeynValue transforms the SVC Cilium type into a bpf SVC type. 289 func LBSVC2ServiceKeynValue(svc loadbalancer.LBSVC) (ServiceKey, []ServiceValue, error) { 290 log.WithFields(logrus.Fields{ 291 "lbFrontend": svc.FE.String(), 292 "lbBackend": svc.BES, 293 }).Debug("converting Cilium load-balancer service (frontend -> backend(s)) into BPF service") 294 fe := l3n4Addr2ServiceKey(svc.FE) 295 296 // Create a list of ServiceValues so we know everything is safe to put in the lb 297 // map 298 besValues := []ServiceValue{} 299 for _, be := range svc.BES { 300 beValue := fe.NewValue().(ServiceValue) 301 if err := beValue.SetAddress(be.IP); err != nil { 302 return nil, nil, err 303 } 304 beValue.SetPort(be.Port) 305 beValue.SetRevNat(int(svc.FE.ID)) 306 beValue.SetWeight(be.Weight) 307 308 besValues = append(besValues, beValue) 309 log.WithFields(logrus.Fields{ 310 "lbFrontend": fe, 311 "lbBackend": beValue, 312 }).Debug("associating frontend -> backend") 313 } 314 log.WithFields(logrus.Fields{ 315 "lbFrontend": svc.FE.String(), 316 "lbBackend": svc.BES, 317 logfields.ServiceID: fe, 318 logfields.Object: logfields.Repr(besValues), 319 }).Debug("converted LBSVC (frontend -> backend(s)), to Service Key and Value") 320 return fe, besValues, nil 321 } 322 323 // L3n4Addr2RevNatKeynValue converts the given L3n4Addr to a RevNatKey and RevNatValue. 324 func L3n4Addr2RevNatKeynValue(svcID loadbalancer.ServiceID, feL3n4Addr loadbalancer.L3n4Addr) (RevNatKey, RevNatValue) { 325 if feL3n4Addr.IsIPv6() { 326 return NewRevNat6Key(uint16(svcID)), NewRevNat6Value(feL3n4Addr.IP, feL3n4Addr.Port) 327 } 328 return NewRevNat4Key(uint16(svcID)), NewRevNat4Value(feL3n4Addr.IP, feL3n4Addr.Port) 329 } 330 331 // serviceKey2L3n4Addr converts the given svcKey to a L3n4Addr. 332 func serviceKey2L3n4Addr(svcKey ServiceKey) *loadbalancer.L3n4Addr { 333 log.WithField(logfields.ServiceID, svcKey).Debug("creating L3n4Addr for ServiceKey") 334 var ( 335 feIP net.IP 336 fePort uint16 337 ) 338 if svcKey.IsIPv6() { 339 svc6Key := svcKey.(*Service6Key) 340 feIP = svc6Key.Address.IP() 341 fePort = svc6Key.Port 342 } else { 343 svc4Key := svcKey.(*Service4Key) 344 feIP = svc4Key.Address.IP() 345 fePort = svc4Key.Port 346 } 347 return loadbalancer.NewL3n4Addr(loadbalancer.NONE, feIP, fePort) 348 } 349 350 // serviceKeynValue2FEnBE converts the given svcKey and svcValue to a frontend in the 351 // form of L3n4AddrID and backend in the form of L3n4Addr. 352 func serviceKeynValue2FEnBE(svcKey ServiceKey, svcValue ServiceValue) (*loadbalancer.L3n4AddrID, *loadbalancer.LBBackEnd) { 353 var ( 354 beIP net.IP 355 svcID loadbalancer.ID 356 bePort uint16 357 beWeight uint16 358 ) 359 360 log.WithFields(logrus.Fields{ 361 logfields.ServiceID: svcKey, 362 logfields.Object: logfields.Repr(svcValue), 363 }).Debug("converting ServiceKey and ServiceValue to frontend and backend") 364 365 if svcKey.IsIPv6() { 366 svc6Val := svcValue.(*Service6Value) 367 svcID = loadbalancer.ID(svc6Val.RevNat) 368 beIP = svc6Val.Address.IP() 369 bePort = svc6Val.Port 370 beWeight = svc6Val.Weight 371 } else { 372 svc4Val := svcValue.(*Service4Value) 373 svcID = loadbalancer.ID(svc4Val.RevNat) 374 beIP = svc4Val.Address.IP() 375 bePort = svc4Val.Port 376 beWeight = svc4Val.Weight 377 } 378 379 feL3n4Addr := serviceKey2L3n4Addr(svcKey) 380 beLBBackEnd := loadbalancer.NewLBBackEnd(0, loadbalancer.NONE, beIP, bePort, beWeight) 381 382 feL3n4AddrID := &loadbalancer.L3n4AddrID{ 383 L3n4Addr: *feL3n4Addr, 384 ID: svcID, 385 } 386 387 return feL3n4AddrID, beLBBackEnd 388 } 389 390 func serviceValue2L3n4Addr(svcVal ServiceValue) *loadbalancer.L3n4Addr { 391 var ( 392 beIP net.IP 393 bePort uint16 394 ) 395 if svcVal.IsIPv6() { 396 svc6Val := svcVal.(*Service6Value) 397 beIP = svc6Val.Address.IP() 398 bePort = svc6Val.Port 399 } else { 400 svc4Val := svcVal.(*Service4Value) 401 beIP = svc4Val.Address.IP() 402 bePort = svc4Val.Port 403 } 404 return loadbalancer.NewL3n4Addr(loadbalancer.NONE, beIP, bePort) 405 } 406 407 // RevNat6Value2L3n4Addr converts the given RevNat6Value to a L3n4Addr. 408 func revNat6Value2L3n4Addr(revNATV *RevNat6Value) *loadbalancer.L3n4Addr { 409 return loadbalancer.NewL3n4Addr(loadbalancer.NONE, revNATV.Address.IP(), revNATV.Port) 410 } 411 412 // revNat4Value2L3n4Addr converts the given RevNat4Value to a L3n4Addr. 413 func revNat4Value2L3n4Addr(revNATV *RevNat4Value) *loadbalancer.L3n4Addr { 414 return loadbalancer.NewL3n4Addr(loadbalancer.NONE, revNATV.Address.IP(), revNATV.Port) 415 } 416 417 // revNatValue2L3n4AddrID converts the given RevNatKey and RevNatValue to a L3n4AddrID. 418 func revNatValue2L3n4AddrID(revNATKey RevNatKey, revNATValue RevNatValue) *loadbalancer.L3n4AddrID { 419 var ( 420 svcID loadbalancer.ID 421 be *loadbalancer.L3n4Addr 422 ) 423 if revNATKey.IsIPv6() { 424 revNat6Key := revNATKey.(*RevNat6Key) 425 svcID = loadbalancer.ID(revNat6Key.Key) 426 427 revNat6Value := revNATValue.(*RevNat6Value) 428 be = revNat6Value2L3n4Addr(revNat6Value) 429 } else { 430 revNat4Key := revNATKey.(*RevNat4Key) 431 svcID = loadbalancer.ID(revNat4Key.Key) 432 433 revNat4Value := revNATValue.(*RevNat4Value) 434 be = revNat4Value2L3n4Addr(revNat4Value) 435 } 436 437 return &loadbalancer.L3n4AddrID{L3n4Addr: *be, ID: svcID} 438 } 439 440 // LBSVC2ServiceKeynValuenBackendValueV2 transforms the SVC Cilium type into a bpf SVC v2 type. 441 func LBSVC2ServiceKeynValuenBackendV2(svc *loadbalancer.LBSVC) (ServiceKeyV2, []ServiceValueV2, []Backend, error) { 442 log.WithFields(logrus.Fields{ 443 "lbFrontend": svc.FE.String(), 444 "lbBackend": svc.BES, 445 }).Debug("converting Cilium load-balancer service (frontend -> backend(s)) into BPF service v2") 446 svcKey := l3n4Addr2ServiceKeyV2(svc.FE) 447 448 backends := []Backend{} 449 svcValues := []ServiceValueV2{} 450 for _, be := range svc.BES { 451 svcValue := svcKey.NewValue().(ServiceValueV2) 452 backend, err := LBBackEnd2Backend(be) 453 if err != nil { 454 return nil, nil, nil, err 455 } 456 457 svcValue.SetRevNat(int(svc.FE.ID)) 458 svcValue.SetWeight(be.Weight) 459 svcValue.SetBackendID(loadbalancer.BackendID(be.ID)) 460 461 backends = append(backends, backend) 462 svcValues = append(svcValues, svcValue) 463 log.WithFields(logrus.Fields{ 464 "lbFrontend": svcKey, 465 "lbBackend": svcValue, 466 }).Debug("associating frontend -> backend") 467 } 468 log.WithFields(logrus.Fields{ 469 "lbFrontend": svc.FE.String(), 470 "lbBackend": svc.BES, 471 logfields.ServiceID: svcKey, 472 logfields.Object: logfields.Repr(svcValues), 473 }).Debug("converted LBSVC (frontend -> backend(s)), to ServiceKeyV2, ServiceValueV2 and Backend") 474 return svcKey, svcValues, backends, nil 475 } 476 477 // serviceKey2L3n4Addr converts the given svcKey to a L3n4Addr. 478 func serviceKey2L3n4AddrV2(svcKey ServiceKeyV2) *loadbalancer.L3n4Addr { 479 log.WithField(logfields.ServiceID, svcKey).Debug("creating L3n4Addr for ServiceKeyV2") 480 481 feProto := loadbalancer.NONE 482 feIP := svcKey.GetAddress() 483 fePort := svcKey.GetPort() 484 485 return loadbalancer.NewL3n4Addr(feProto, feIP, fePort) 486 } 487 488 func serviceKeynValuenBackendValue2FEnBE(svcKey ServiceKeyV2, svcValue ServiceValueV2, 489 backendID loadbalancer.BackendID, backend BackendValue) (*loadbalancer.L3n4AddrID, *loadbalancer.LBBackEnd) { 490 491 log.WithFields(logrus.Fields{ 492 logfields.ServiceID: svcKey, 493 logfields.Object: logfields.Repr(svcValue), 494 }).Debug("converting ServiceKey, ServiceValue and Backend to frontend and backend v2") 495 var beLBBackEnd *loadbalancer.LBBackEnd 496 497 svcID := loadbalancer.ID(svcValue.GetRevNat()) 498 feL3n4Addr := serviceKey2L3n4AddrV2(svcKey) 499 feL3n4AddrID := &loadbalancer.L3n4AddrID{ 500 L3n4Addr: *feL3n4Addr, 501 ID: svcID, 502 } 503 504 if backendID != 0 { 505 beIP := backend.GetAddress() 506 bePort := backend.GetPort() 507 beWeight := svcValue.GetWeight() 508 beProto := loadbalancer.NONE 509 beLBBackEnd = loadbalancer.NewLBBackEnd(backendID, beProto, beIP, bePort, beWeight) 510 } 511 512 return feL3n4AddrID, beLBBackEnd 513 } 514 515 // l3n4Addr2ServiceKeyV2 converts the given l3n4Addr to a ServiceKey (v2) with the slave ID 516 // set to 0. 517 func l3n4Addr2ServiceKeyV2(l3n4Addr loadbalancer.L3n4AddrID) ServiceKeyV2 { 518 log.WithField(logfields.L3n4AddrID, l3n4Addr).Debug("converting L3n4Addr to ServiceKeyV2") 519 if l3n4Addr.IsIPv6() { 520 return NewService6KeyV2(l3n4Addr.IP, l3n4Addr.Port, u8proto.ANY, 0) 521 } 522 523 return NewService4KeyV2(l3n4Addr.IP, l3n4Addr.Port, u8proto.ANY, 0) 524 } 525 526 // LBBackEnd2Backend converts the loadbalancer backend type into a backend 527 // with a BPF key backing. 528 func LBBackEnd2Backend(be loadbalancer.LBBackEnd) (Backend, error) { 529 if be.IsIPv6() { 530 return NewBackend6(loadbalancer.BackendID(be.ID), be.IP, be.Port, u8proto.ANY) 531 } 532 533 return NewBackend4(loadbalancer.BackendID(be.ID), be.IP, be.Port, u8proto.ANY) 534 }