github.com/cilium/cilium@v1.16.2/pkg/testutils/mockmaps/lbmap.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package mockmaps
     5  
     6  import (
     7  	"fmt"
     8  	"net"
     9  
    10  	"github.com/cilium/cilium/pkg/cidr"
    11  	cmtypes "github.com/cilium/cilium/pkg/clustermesh/types"
    12  	datapathTypes "github.com/cilium/cilium/pkg/datapath/types"
    13  	"github.com/cilium/cilium/pkg/ip"
    14  	lb "github.com/cilium/cilium/pkg/loadbalancer"
    15  	"github.com/cilium/cilium/pkg/lock"
    16  	"github.com/cilium/cilium/pkg/maps/lbmap"
    17  )
    18  
    19  type LBMockMap struct {
    20  	lock.Mutex
    21  	BackendByID            map[lb.BackendID]*lb.Backend
    22  	ServiceByID            map[uint16]*lb.SVC
    23  	AffinityMatch          datapathTypes.BackendIDByServiceIDSet
    24  	SourceRanges           datapathTypes.SourceRangeSetByServiceID
    25  	DummyMaglevTable       map[uint16]int // svcID => backends count
    26  	SvcActiveBackendsCount map[uint16]int
    27  	SockRevNat4            map[lbmap.SockRevNat4Key]lbmap.SockRevNat4Value
    28  	SockRevNat6            map[lbmap.SockRevNat6Key]lbmap.SockRevNat6Value
    29  }
    30  
    31  func NewLBMockMap() *LBMockMap {
    32  	return &LBMockMap{
    33  		BackendByID:            map[lb.BackendID]*lb.Backend{},
    34  		ServiceByID:            map[uint16]*lb.SVC{},
    35  		AffinityMatch:          datapathTypes.BackendIDByServiceIDSet{},
    36  		SourceRanges:           datapathTypes.SourceRangeSetByServiceID{},
    37  		DummyMaglevTable:       map[uint16]int{},
    38  		SvcActiveBackendsCount: map[uint16]int{},
    39  		SockRevNat4:            map[lbmap.SockRevNat4Key]lbmap.SockRevNat4Value{},
    40  		SockRevNat6:            map[lbmap.SockRevNat6Key]lbmap.SockRevNat6Value{},
    41  	}
    42  }
    43  
    44  func (m *LBMockMap) UpsertService(p *datapathTypes.UpsertServiceParams) error {
    45  	m.Lock()
    46  	defer m.Unlock()
    47  
    48  	backendIDs := p.GetOrderedBackends()
    49  	backendsList := make([]*lb.Backend, 0, len(backendIDs))
    50  	for _, backendID := range backendIDs {
    51  		b, found := m.BackendByID[backendID]
    52  		if !found {
    53  			return fmt.Errorf("backend %d not found", p.ID)
    54  		}
    55  		backendsList = append(backendsList, b)
    56  	}
    57  	backends := p.ActiveBackends
    58  	if len(p.PreferredBackends) > 0 {
    59  		backends = p.PreferredBackends
    60  	}
    61  	if p.UseMaglev && len(backends) != 0 {
    62  		if err := m.upsertMaglevLookupTable(p.ID, backends, p.IPv6); err != nil {
    63  			return err
    64  		}
    65  	}
    66  	svc, found := m.ServiceByID[p.ID]
    67  	if !found {
    68  		frontend := lb.NewL3n4AddrID(lb.NONE, cmtypes.MustAddrClusterFromIP(p.IP), p.Port, p.Scope, lb.ID(p.ID))
    69  		svc = &lb.SVC{Frontend: *frontend}
    70  	} else {
    71  		if p.PrevBackendsCount != len(svc.Backends) {
    72  			return fmt.Errorf("Invalid backends count: %d vs %d", p.PrevBackendsCount, len(svc.Backends))
    73  		}
    74  	}
    75  	svc.Backends = backendsList
    76  	svc.SessionAffinity = p.SessionAffinity
    77  	svc.SessionAffinityTimeoutSec = p.SessionAffinityTimeoutSec
    78  	svc.Type = p.Type
    79  	svc.Name = p.Name
    80  
    81  	m.ServiceByID[p.ID] = svc
    82  	m.SvcActiveBackendsCount[p.ID] = len(p.ActiveBackends)
    83  
    84  	return nil
    85  }
    86  
    87  func (m *LBMockMap) upsertMaglevLookupTable(svcID uint16, backends map[string]*lb.Backend, ipv6 bool) error {
    88  	m.DummyMaglevTable[svcID] = len(backends)
    89  	return nil
    90  }
    91  
    92  func (m *LBMockMap) UpsertMaglevLookupTable(svcID uint16, backends map[string]*lb.Backend, ipv6 bool) error {
    93  	m.Lock()
    94  	defer m.Unlock()
    95  	return m.upsertMaglevLookupTable(svcID, backends, ipv6)
    96  }
    97  
    98  func (*LBMockMap) IsMaglevLookupTableRecreated(ipv6 bool) bool {
    99  	return true
   100  }
   101  
   102  func (m *LBMockMap) DeleteService(addr lb.L3n4AddrID, backendCount int, maglev bool, natPolicy lb.SVCNatPolicy) error {
   103  	m.Lock()
   104  	defer m.Unlock()
   105  	svc, found := m.ServiceByID[uint16(addr.ID)]
   106  	if !found {
   107  		return fmt.Errorf("Service not found %+v", addr)
   108  	}
   109  	if count := len(svc.Backends); count != backendCount {
   110  		return fmt.Errorf("Invalid backends count: %d vs %d",
   111  			count, backendCount)
   112  	}
   113  
   114  	delete(m.ServiceByID, uint16(addr.ID))
   115  
   116  	return nil
   117  }
   118  
   119  func (m *LBMockMap) AddBackend(b *lb.Backend, ipv6 bool) error {
   120  	m.Lock()
   121  	defer m.Unlock()
   122  	id := b.ID
   123  	port := b.Port
   124  
   125  	// Backends can be added to both v4 and v6 lb maps (when nat64 policies
   126  	// are enabled).
   127  	if _, found := m.BackendByID[id]; found && !b.L3n4Addr.IsIPv6() && !ipv6 {
   128  		return fmt.Errorf("Backend %d already exists", id)
   129  	}
   130  
   131  	be := lb.NewBackendWithState(id, b.Protocol, b.AddrCluster, port, b.ZoneID, b.State)
   132  	m.BackendByID[id] = be
   133  
   134  	return nil
   135  }
   136  
   137  func (m *LBMockMap) UpdateBackendWithState(b *lb.Backend) error {
   138  	m.Lock()
   139  	defer m.Unlock()
   140  	id := b.ID
   141  
   142  	be, found := m.BackendByID[id]
   143  	if !found {
   144  		return fmt.Errorf("update failed : backend %d doesn't exist", id)
   145  	}
   146  	if b.ID != be.ID || b.Port != be.Port || !b.AddrCluster.Equal(be.AddrCluster) {
   147  		return fmt.Errorf("backend in the map  %+v doesn't match %+v: only backend"+
   148  			"state can be updated", be.String(), b.String())
   149  	}
   150  	be.State = b.State
   151  	return nil
   152  }
   153  
   154  func (m *LBMockMap) DeleteBackendByID(id lb.BackendID) error {
   155  	m.Lock()
   156  	defer m.Unlock()
   157  	if _, found := m.BackendByID[id]; !found {
   158  		return fmt.Errorf("Backend %d does not exist", id)
   159  	}
   160  
   161  	delete(m.BackendByID, id)
   162  
   163  	return nil
   164  }
   165  
   166  func (m *LBMockMap) DumpServiceMaps() ([]*lb.SVC, []error) {
   167  	m.Lock()
   168  	defer m.Unlock()
   169  	list := make([]*lb.SVC, 0, len(m.ServiceByID))
   170  	for _, svc := range m.ServiceByID {
   171  		list = append(list, svc)
   172  	}
   173  	return list, nil
   174  }
   175  
   176  func (m *LBMockMap) DumpBackendMaps() ([]*lb.Backend, error) {
   177  	m.Lock()
   178  	defer m.Unlock()
   179  	list := make([]*lb.Backend, 0, len(m.BackendByID))
   180  	for _, backend := range m.BackendByID {
   181  		list = append(list, backend)
   182  	}
   183  	return list, nil
   184  }
   185  
   186  func (m *LBMockMap) AddAffinityMatch(revNATID uint16, backendID lb.BackendID) error {
   187  	m.Lock()
   188  	defer m.Unlock()
   189  	if _, ok := m.AffinityMatch[revNATID]; !ok {
   190  		m.AffinityMatch[revNATID] = map[lb.BackendID]struct{}{}
   191  	}
   192  	if _, ok := m.AffinityMatch[revNATID][backendID]; ok {
   193  		return fmt.Errorf("Backend %d already exists in %d affinity map",
   194  			backendID, revNATID)
   195  	}
   196  	m.AffinityMatch[revNATID][backendID] = struct{}{}
   197  	return nil
   198  }
   199  
   200  func (m *LBMockMap) DeleteAffinityMatch(revNATID uint16, backendID lb.BackendID) error {
   201  	m.Lock()
   202  	defer m.Unlock()
   203  	if _, ok := m.AffinityMatch[revNATID]; !ok {
   204  		return fmt.Errorf("Affinity map for %d does not exist", revNATID)
   205  	}
   206  	if _, ok := m.AffinityMatch[revNATID][backendID]; !ok {
   207  		return fmt.Errorf("Backend %d does not exist in %d affinity map",
   208  			backendID, revNATID)
   209  	}
   210  	delete(m.AffinityMatch[revNATID], backendID)
   211  	if len(m.AffinityMatch[revNATID]) == 0 {
   212  		delete(m.AffinityMatch, revNATID)
   213  	}
   214  	return nil
   215  }
   216  
   217  func (m *LBMockMap) DumpAffinityMatches() (datapathTypes.BackendIDByServiceIDSet, error) {
   218  	return m.AffinityMatch, nil
   219  }
   220  
   221  func (m *LBMockMap) UpdateSourceRanges(revNATID uint16, prevRanges []*cidr.CIDR,
   222  	ranges []*cidr.CIDR, ipv6 bool) error {
   223  	m.Lock()
   224  	defer m.Unlock()
   225  
   226  	if len(prevRanges) == 0 {
   227  		m.SourceRanges[revNATID] = []*cidr.CIDR{}
   228  	}
   229  	if len(prevRanges) != len(m.SourceRanges[revNATID]) {
   230  		return fmt.Errorf("Inconsistent view of source ranges")
   231  	}
   232  	srcRanges := []*cidr.CIDR{}
   233  	for _, cidr := range ranges {
   234  		if ip.IsIPv6(cidr.IP) == !ipv6 {
   235  			continue
   236  		}
   237  		srcRanges = append(srcRanges, cidr)
   238  	}
   239  	m.SourceRanges[revNATID] = srcRanges
   240  
   241  	return nil
   242  }
   243  
   244  func (m *LBMockMap) DumpSourceRanges(ipv6 bool) (datapathTypes.SourceRangeSetByServiceID, error) {
   245  	return m.SourceRanges, nil
   246  }
   247  
   248  func (m *LBMockMap) ExistsSockRevNat(cookie uint64, addr net.IP, port uint16) bool {
   249  	if addr.To4() != nil {
   250  		key := lbmap.NewSockRevNat4Key(cookie, addr, port)
   251  		if _, ok := m.SockRevNat4[*key]; ok {
   252  			return true
   253  		}
   254  	} else {
   255  		key := lbmap.NewSockRevNat6Key(cookie, addr, port)
   256  		if _, ok := m.SockRevNat6[*key]; ok {
   257  			return true
   258  		}
   259  	}
   260  
   261  	return false
   262  }