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  }