github.com/cilium/cilium@v1.16.2/pkg/service/service_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package service
     5  
     6  import (
     7  	"errors"
     8  	"net"
     9  	"net/netip"
    10  	"syscall"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  	"github.com/vishvananda/netlink"
    16  	"golang.org/x/exp/maps"
    17  	"golang.org/x/sys/unix"
    18  	"k8s.io/apimachinery/pkg/util/sets"
    19  
    20  	"github.com/cilium/cilium/api/v1/models"
    21  	"github.com/cilium/cilium/pkg/cidr"
    22  	cmtypes "github.com/cilium/cilium/pkg/clustermesh/types"
    23  	datapathOpt "github.com/cilium/cilium/pkg/datapath/option"
    24  	datapathTypes "github.com/cilium/cilium/pkg/datapath/types"
    25  	"github.com/cilium/cilium/pkg/k8s"
    26  	lb "github.com/cilium/cilium/pkg/loadbalancer"
    27  	"github.com/cilium/cilium/pkg/maps/lbmap"
    28  	monitorAgent "github.com/cilium/cilium/pkg/monitor/agent"
    29  	"github.com/cilium/cilium/pkg/monitor/agent/consumer"
    30  	"github.com/cilium/cilium/pkg/monitor/agent/listener"
    31  	nodeTypes "github.com/cilium/cilium/pkg/node/types"
    32  	"github.com/cilium/cilium/pkg/option"
    33  	"github.com/cilium/cilium/pkg/service/healthserver"
    34  	"github.com/cilium/cilium/pkg/testutils/mockmaps"
    35  	testsockets "github.com/cilium/cilium/pkg/testutils/sockets"
    36  )
    37  
    38  func TestLocalRedirectServiceExistsError(t *testing.T) {
    39  	addrCluster1 := cmtypes.MustParseAddrCluster("1.2.3.4")
    40  	addrCluster2 := cmtypes.MustParseAddrCluster("5.6.7.8")
    41  	name1 := "my-svc-1"
    42  	name2 := "my-svc-2"
    43  
    44  	// same frontend, same name
    45  	err1 := NewErrLocalRedirectServiceExists(
    46  		*lb.NewL3n4AddrID(lb.TCP, addrCluster1, 8080, lb.ScopeInternal, 1),
    47  		lb.ServiceName{Namespace: "default", Name: name1},
    48  	)
    49  	err2 := NewErrLocalRedirectServiceExists(
    50  		*lb.NewL3n4AddrID(lb.TCP, addrCluster1, 8080, lb.ScopeInternal, 1),
    51  		lb.ServiceName{Namespace: "default", Name: name1},
    52  	)
    53  	assert.Equal(t, err1, err2)
    54  	assert.True(t, errors.Is(err1, err2))
    55  
    56  	// same frontend, different name
    57  	err1 = NewErrLocalRedirectServiceExists(
    58  		*lb.NewL3n4AddrID(lb.TCP, addrCluster1, 8080, lb.ScopeInternal, 1),
    59  		lb.ServiceName{Namespace: "default", Name: name1},
    60  	)
    61  	err2 = NewErrLocalRedirectServiceExists(
    62  		*lb.NewL3n4AddrID(lb.TCP, addrCluster1, 8080, lb.ScopeInternal, 1),
    63  		lb.ServiceName{Namespace: "default", Name: name2},
    64  	)
    65  	assert.NotEqual(t, err1, err2)
    66  	assert.False(t, errors.Is(err1, err2))
    67  
    68  	// different frontend, same name
    69  	err1 = NewErrLocalRedirectServiceExists(
    70  		*lb.NewL3n4AddrID(lb.TCP, addrCluster1, 8080, lb.ScopeInternal, 1),
    71  		lb.ServiceName{Namespace: "default", Name: name1},
    72  	)
    73  	err2 = NewErrLocalRedirectServiceExists(
    74  		*lb.NewL3n4AddrID(lb.TCP, addrCluster2, 8080, lb.ScopeInternal, 1),
    75  		lb.ServiceName{Namespace: "default", Name: name1},
    76  	)
    77  	assert.NotEqual(t, err1, err2)
    78  	assert.False(t, errors.Is(err1, err2))
    79  
    80  	// different frontend, different name
    81  	err1 = NewErrLocalRedirectServiceExists(
    82  		*lb.NewL3n4AddrID(lb.TCP, addrCluster1, 8080, lb.ScopeInternal, 1),
    83  		lb.ServiceName{Namespace: "default", Name: name1},
    84  	)
    85  	err2 = NewErrLocalRedirectServiceExists(
    86  		*lb.NewL3n4AddrID(lb.TCP, addrCluster2, 8080, lb.ScopeInternal, 1),
    87  		lb.ServiceName{Namespace: "default", Name: name2},
    88  	)
    89  	assert.NotEqual(t, err1, err2)
    90  	assert.False(t, errors.Is(err1, err2))
    91  
    92  	// different error types
    93  	err1 = NewErrLocalRedirectServiceExists(
    94  		*lb.NewL3n4AddrID(lb.TCP, addrCluster1, 8080, lb.ScopeInternal, 1),
    95  		lb.ServiceName{Namespace: "default", Name: name1},
    96  	)
    97  	err2 = errors.New("another error")
    98  	assert.NotEqual(t, err1, err2)
    99  	assert.False(t, errors.Is(err1, err2))
   100  
   101  	// different error types
   102  	err1 = errors.New("another error")
   103  	err2 = NewErrLocalRedirectServiceExists(
   104  		*lb.NewL3n4AddrID(lb.TCP, addrCluster1, 8080, lb.ScopeInternal, 1),
   105  		lb.ServiceName{Namespace: "default", Name: name1},
   106  	)
   107  	assert.NotEqual(t, err1, err2)
   108  	assert.False(t, errors.Is(err1, err2))
   109  
   110  	// an error is nil
   111  	err1 = NewErrLocalRedirectServiceExists(
   112  		*lb.NewL3n4AddrID(lb.TCP, addrCluster1, 8080, lb.ScopeInternal, 1),
   113  		lb.ServiceName{Namespace: "default", Name: name1},
   114  	)
   115  	err2 = nil
   116  	assert.NotEqual(t, err1, err2)
   117  	assert.False(t, errors.Is(err1, err2))
   118  
   119  	// an error is nil
   120  	err1 = nil
   121  	err2 = NewErrLocalRedirectServiceExists(
   122  		*lb.NewL3n4AddrID(lb.TCP, addrCluster1, 8080, lb.ScopeInternal, 1),
   123  		lb.ServiceName{Namespace: "default", Name: name1},
   124  	)
   125  	assert.NotEqual(t, err1, err2)
   126  	assert.False(t, errors.Is(err1, err2))
   127  
   128  	// We don't match against strings. It must be the sentinel value.
   129  	err1 = NewErrLocalRedirectServiceExists(
   130  		*lb.NewL3n4AddrID(lb.TCP, addrCluster1, 8080, lb.ScopeInternal, 1),
   131  		lb.ServiceName{Namespace: "default", Name: name1},
   132  	)
   133  	err2 = errors.New(err1.Error())
   134  	assert.NotEqual(t, err1, err2)
   135  	assert.False(t, errors.Is(err1, err2))
   136  }
   137  
   138  type ManagerTestSuite struct {
   139  	svc                         *Service
   140  	lbmap                       *mockmaps.LBMockMap // for accessing public fields
   141  	svcHealth                   *healthserver.MockHealthHTTPServerFactory
   142  	prevOptionSessionAffinity   bool
   143  	prevOptionLBSourceRanges    bool
   144  	prevOptionNPAlgo            string
   145  	prevOptionDPMode            string
   146  	prevOptionExternalClusterIP bool
   147  	ipv6                        bool
   148  }
   149  
   150  var (
   151  	surrogateFE    = *lb.NewL3n4AddrID(lb.TCP, cmtypes.MustParseAddrCluster("0.0.0.0"), 80, lb.ScopeExternal, 0)
   152  	surrogateFEv6  = *lb.NewL3n4AddrID(lb.TCP, cmtypes.MustParseAddrCluster("::"), 80, lb.ScopeExternal, 0)
   153  	frontend1      = *lb.NewL3n4AddrID(lb.TCP, cmtypes.MustParseAddrCluster("1.1.1.1"), 80, lb.ScopeExternal, 0)
   154  	frontend1_8080 = *lb.NewL3n4AddrID(lb.TCP, cmtypes.MustParseAddrCluster("1.1.1.1"), 8080, lb.ScopeExternal, 0)
   155  	frontend2      = *lb.NewL3n4AddrID(lb.TCP, cmtypes.MustParseAddrCluster("1.1.1.2"), 80, lb.ScopeExternal, 0)
   156  	frontend3      = *lb.NewL3n4AddrID(lb.TCP, cmtypes.MustParseAddrCluster("f00d::1"), 80, lb.ScopeExternal, 0)
   157  
   158  	backends1, backends2, backends3, backends4, backends5, backends6 []*lb.Backend
   159  )
   160  
   161  func setupManagerTestSuite(tb testing.TB) *ManagerTestSuite {
   162  	m := &ManagerTestSuite{}
   163  	serviceIDAlloc.resetLocalID()
   164  	backendIDAlloc.resetLocalID()
   165  
   166  	m.lbmap = mockmaps.NewLBMockMap()
   167  	m.newServiceMock(m.lbmap)
   168  
   169  	m.svcHealth = healthserver.NewMockHealthHTTPServerFactory()
   170  	m.svc.healthServer = healthserver.WithHealthHTTPServerFactory(m.svcHealth)
   171  
   172  	m.prevOptionSessionAffinity = option.Config.EnableSessionAffinity
   173  	option.Config.EnableSessionAffinity = true
   174  
   175  	m.prevOptionLBSourceRanges = option.Config.EnableSVCSourceRangeCheck
   176  	option.Config.EnableSVCSourceRangeCheck = true
   177  
   178  	m.prevOptionNPAlgo = option.Config.NodePortAlg
   179  	m.prevOptionDPMode = option.Config.DatapathMode
   180  	m.prevOptionExternalClusterIP = option.Config.ExternalClusterIP
   181  
   182  	m.ipv6 = option.Config.EnableIPv6
   183  	backends1 = []*lb.Backend{
   184  		lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.1"), 8080),
   185  		lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.2"), 8080),
   186  	}
   187  	backends2 = []*lb.Backend{
   188  		lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.2"), 8080),
   189  		lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.3"), 8080),
   190  	}
   191  	backends3 = []*lb.Backend{
   192  		lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("fd00::2"), 8080),
   193  		lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("fd00::3"), 8080),
   194  	}
   195  	backends4 = []*lb.Backend{
   196  		lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.4"), 8080),
   197  	}
   198  	backends5 = []*lb.Backend{
   199  		lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.5"), 8080),
   200  		lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.6"), 8080),
   201  	}
   202  	backends6 = []*lb.Backend{
   203  		lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.7"), 8080),
   204  	}
   205  
   206  	tb.Cleanup(func() {
   207  		serviceIDAlloc.resetLocalID()
   208  		backendIDAlloc.resetLocalID()
   209  		option.Config.EnableSessionAffinity = m.prevOptionSessionAffinity
   210  		option.Config.EnableSVCSourceRangeCheck = m.prevOptionLBSourceRanges
   211  		option.Config.NodePortAlg = m.prevOptionNPAlgo
   212  		option.Config.DatapathMode = m.prevOptionDPMode
   213  		option.Config.ExternalClusterIP = m.prevOptionExternalClusterIP
   214  		option.Config.EnableIPv6 = m.ipv6
   215  	})
   216  
   217  	return m
   218  }
   219  
   220  func (m *ManagerTestSuite) newServiceMock(lbmap datapathTypes.LBMap) {
   221  	m.svc = newService(&FakeMonitorAgent{}, lbmap, nil)
   222  	m.svc.backendConnectionHandler = testsockets.NewMockSockets(make([]*testsockets.MockSocket, 0))
   223  }
   224  
   225  func TestUpsertAndDeleteService(t *testing.T) {
   226  	m := setupManagerTestSuite(t)
   227  	m.testUpsertAndDeleteService(t)
   228  }
   229  
   230  func TestUpsertAndDeleteServiceWithoutIPv6(t *testing.T) {
   231  	m := setupManagerTestSuite(t)
   232  
   233  	option.Config.EnableIPv6 = false
   234  	m.testUpsertAndDeleteService(t)
   235  }
   236  
   237  func TestUpsertAndDeleteServiceNat46(t *testing.T) {
   238  	m := setupManagerTestSuite(t)
   239  
   240  	option.Config.EnableIPv4 = true
   241  	option.Config.EnableIPv6 = true
   242  	option.Config.NodePortNat46X64 = true
   243  	m.testUpsertAndDeleteService46(t)
   244  }
   245  
   246  func TestUpsertAndDeleteServiceNat64(t *testing.T) {
   247  	m := setupManagerTestSuite(t)
   248  
   249  	option.Config.EnableIPv4 = true
   250  	option.Config.EnableIPv6 = true
   251  	option.Config.NodePortNat46X64 = true
   252  	m.testUpsertAndDeleteService64(t)
   253  }
   254  
   255  func (m *ManagerTestSuite) testUpsertAndDeleteService46(t *testing.T) {
   256  	// Should create a new v4 service with two v6 backends
   257  	p := &lb.SVC{
   258  		Frontend:         frontend1,
   259  		Backends:         backends3,
   260  		Type:             lb.SVCTypeNodePort,
   261  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
   262  		IntTrafficPolicy: lb.SVCTrafficPolicyCluster,
   263  		Name:             lb.ServiceName{Name: "svc1", Namespace: "ns1"},
   264  	}
   265  	created, id1, err := m.svc.UpsertService(p)
   266  	require.Nil(t, err)
   267  	require.Equal(t, true, created)
   268  	require.Equal(t, lb.ID(1), id1)
   269  	require.Equal(t, 2, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
   270  	require.Equal(t, 2, len(m.lbmap.BackendByID))
   271  	require.Equal(t, "svc1", m.svc.svcByID[id1].svcName.Name)
   272  	require.Equal(t, "ns1", m.svc.svcByID[id1].svcName.Namespace)
   273  	require.Equal(t, lb.SVCNatPolicyNat46, m.svc.svcByID[id1].svcNatPolicy)
   274  
   275  	// Should delete both backends of service
   276  	p.Backends = nil
   277  	created, id2, err := m.svc.UpsertService(p)
   278  	require.Nil(t, err)
   279  	require.Equal(t, false, created)
   280  	require.Equal(t, id1, id2)
   281  	require.Equal(t, 0, len(m.lbmap.ServiceByID[uint16(id2)].Backends))
   282  	require.Equal(t, 0, len(m.lbmap.BackendByID))
   283  	require.Equal(t, "svc1", m.svc.svcByID[id2].svcName.Name)
   284  	require.Equal(t, "ns1", m.svc.svcByID[id2].svcName.Namespace)
   285  	require.Equal(t, lb.SVCNatPolicyNone, m.svc.svcByID[id2].svcNatPolicy)
   286  
   287  	// Should delete the remaining service
   288  	found, err := m.svc.DeleteServiceByID(lb.ServiceID(id1))
   289  	require.Nil(t, err)
   290  	require.Equal(t, true, found)
   291  	require.Equal(t, 0, len(m.lbmap.ServiceByID))
   292  	require.Equal(t, 0, len(m.lbmap.BackendByID))
   293  }
   294  
   295  func (m *ManagerTestSuite) testUpsertAndDeleteService64(t *testing.T) {
   296  	// Should create a new v6 service with two v4 backends
   297  	p := &lb.SVC{
   298  		Frontend:         frontend3,
   299  		Backends:         backends1,
   300  		Type:             lb.SVCTypeNodePort,
   301  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
   302  		IntTrafficPolicy: lb.SVCTrafficPolicyCluster,
   303  		Name:             lb.ServiceName{Name: "svc1", Namespace: "ns1"},
   304  	}
   305  	created, id1, err := m.svc.UpsertService(p)
   306  	require.Nil(t, err)
   307  	require.Equal(t, true, created)
   308  	require.Equal(t, lb.ID(1), id1)
   309  	require.Equal(t, 2, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
   310  	require.Equal(t, 2, len(m.lbmap.BackendByID))
   311  	require.Equal(t, "svc1", m.svc.svcByID[id1].svcName.Name)
   312  	require.Equal(t, "ns1", m.svc.svcByID[id1].svcName.Namespace)
   313  	require.Equal(t, lb.SVCNatPolicyNat64, m.svc.svcByID[id1].svcNatPolicy)
   314  
   315  	// Should delete both backends of service
   316  	p.Backends = nil
   317  	created, id2, err := m.svc.UpsertService(p)
   318  	require.Nil(t, err)
   319  	require.Equal(t, false, created)
   320  	require.Equal(t, id1, id2)
   321  	require.Equal(t, 0, len(m.lbmap.ServiceByID[uint16(id2)].Backends))
   322  	require.Equal(t, 0, len(m.lbmap.BackendByID))
   323  	require.Equal(t, "svc1", m.svc.svcByID[id2].svcName.Name)
   324  	require.Equal(t, "ns1", m.svc.svcByID[id2].svcName.Namespace)
   325  	require.Equal(t, lb.SVCNatPolicyNone, m.svc.svcByID[id2].svcNatPolicy)
   326  
   327  	// Should delete the remaining service
   328  	found, err := m.svc.DeleteServiceByID(lb.ServiceID(id1))
   329  	require.Nil(t, err)
   330  	require.Equal(t, true, found)
   331  	require.Equal(t, 0, len(m.lbmap.ServiceByID))
   332  	require.Equal(t, 0, len(m.lbmap.BackendByID))
   333  }
   334  
   335  func (m *ManagerTestSuite) testUpsertAndDeleteService(t *testing.T) {
   336  	// Should create a new service with two backends and session affinity
   337  	p := &lb.SVC{
   338  		Frontend:                  frontend1,
   339  		Backends:                  backends1,
   340  		Type:                      lb.SVCTypeNodePort,
   341  		ExtTrafficPolicy:          lb.SVCTrafficPolicyCluster,
   342  		IntTrafficPolicy:          lb.SVCTrafficPolicyCluster,
   343  		SessionAffinity:           true,
   344  		SessionAffinityTimeoutSec: 100,
   345  		Name:                      lb.ServiceName{Name: "svc1", Namespace: "ns1"},
   346  	}
   347  	created, id1, err := m.svc.UpsertService(p)
   348  	require.Nil(t, err)
   349  	require.Equal(t, true, created)
   350  	require.Equal(t, lb.ID(1), id1)
   351  	require.Equal(t, 2, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
   352  	require.Equal(t, 2, len(m.lbmap.BackendByID))
   353  	require.Equal(t, "svc1", m.svc.svcByID[id1].svcName.Name)
   354  	require.Equal(t, "ns1", m.svc.svcByID[id1].svcName.Namespace)
   355  	require.Equal(t, true, m.svc.svcByID[id1].sessionAffinity)
   356  	require.Equal(t, uint32(100), m.svc.svcByID[id1].sessionAffinityTimeoutSec)
   357  	require.Equal(t, true, m.lbmap.ServiceByID[uint16(id1)].SessionAffinity)
   358  	require.Equal(t, uint32(100), m.lbmap.ServiceByID[uint16(id1)].SessionAffinityTimeoutSec)
   359  	require.Equal(t, 2, len(m.lbmap.AffinityMatch[uint16(id1)]))
   360  	for bID := range m.lbmap.BackendByID {
   361  		require.Equal(t, struct{}{}, m.lbmap.AffinityMatch[uint16(id1)][bID])
   362  	}
   363  
   364  	// Should remove session affinity
   365  	p.SessionAffinity = false
   366  	created, id1, err = m.svc.UpsertService(p)
   367  	require.Nil(t, err)
   368  	require.Equal(t, false, created)
   369  	require.Equal(t, lb.ID(1), id1)
   370  	require.Equal(t, 2, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
   371  	require.Equal(t, 2, len(m.lbmap.BackendByID))
   372  	require.Equal(t, "svc1", m.svc.svcByID[id1].svcName.Name)
   373  	require.Equal(t, "ns1", m.svc.svcByID[id1].svcName.Namespace)
   374  	require.Equal(t, 0, len(m.lbmap.AffinityMatch[uint16(id1)]))
   375  	require.Equal(t, false, m.svc.svcByID[id1].sessionAffinity)
   376  	require.Equal(t, false, m.lbmap.ServiceByID[uint16(id1)].SessionAffinity)
   377  	// TODO(brb) test that backends are the same
   378  	// TODO(brb) check that .backends =~ .backendsByHash
   379  
   380  	// Should remove one backend and enable session affinity
   381  	p.Backends = backends1[0:1]
   382  	p.SessionAffinity = true
   383  	p.SessionAffinityTimeoutSec = 200
   384  	created, id1, err = m.svc.UpsertService(p)
   385  	require.Nil(t, err)
   386  	require.Equal(t, false, created)
   387  	require.Equal(t, lb.ID(1), id1)
   388  	require.Equal(t, 1, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
   389  	require.Equal(t, 1, len(m.lbmap.BackendByID))
   390  	require.Equal(t, "svc1", m.svc.svcByID[id1].svcName.Name)
   391  	require.Equal(t, "ns1", m.svc.svcByID[id1].svcName.Namespace)
   392  	require.Equal(t, true, m.svc.svcByID[id1].sessionAffinity)
   393  	require.Equal(t, uint32(200), m.svc.svcByID[id1].sessionAffinityTimeoutSec)
   394  	require.Equal(t, 1, len(m.lbmap.AffinityMatch[uint16(id1)]))
   395  	for bID := range m.lbmap.BackendByID {
   396  		require.Equal(t, struct{}{}, m.lbmap.AffinityMatch[uint16(id1)][bID])
   397  	}
   398  
   399  	// Should add another service
   400  	require.Nil(t, err)
   401  	cidr1, err := cidr.ParseCIDR("10.0.0.0/8")
   402  	require.Nil(t, err)
   403  	cidr2, err := cidr.ParseCIDR("192.168.1.0/24")
   404  	require.Nil(t, err)
   405  	p2 := &lb.SVC{
   406  		Frontend:                  frontend2,
   407  		Backends:                  backends1,
   408  		Type:                      lb.SVCTypeLoadBalancer,
   409  		ExtTrafficPolicy:          lb.SVCTrafficPolicyCluster,
   410  		IntTrafficPolicy:          lb.SVCTrafficPolicyCluster,
   411  		SessionAffinity:           true,
   412  		SessionAffinityTimeoutSec: 300,
   413  		Name:                      lb.ServiceName{Name: "svc2", Namespace: "ns2"},
   414  		LoadBalancerSourceRanges:  []*cidr.CIDR{cidr1, cidr2},
   415  	}
   416  	created, id2, err := m.svc.UpsertService(p2)
   417  	require.Nil(t, err)
   418  	require.Equal(t, true, created)
   419  	require.Equal(t, lb.ID(2), id2)
   420  	require.Equal(t, 2, len(m.lbmap.ServiceByID[uint16(id2)].Backends))
   421  	require.Equal(t, 2, len(m.lbmap.BackendByID))
   422  	require.Equal(t, "svc2", m.svc.svcByID[id2].svcName.Name)
   423  	require.Equal(t, "ns2", m.svc.svcByID[id2].svcName.Namespace)
   424  	require.Equal(t, 2, len(m.lbmap.AffinityMatch[uint16(id2)]))
   425  	require.Equal(t, 2, len(m.lbmap.SourceRanges[uint16(id2)]))
   426  
   427  	// Should add IPv6 service only if IPv6 is enabled
   428  	require.Nil(t, err)
   429  	cidr1, err = cidr.ParseCIDR("fd00::/8")
   430  	require.Nil(t, err)
   431  	p3 := &lb.SVC{
   432  		Frontend:                  frontend3,
   433  		Backends:                  backends3,
   434  		Type:                      lb.SVCTypeLoadBalancer,
   435  		ExtTrafficPolicy:          lb.SVCTrafficPolicyCluster,
   436  		IntTrafficPolicy:          lb.SVCTrafficPolicyCluster,
   437  		SessionAffinity:           true,
   438  		SessionAffinityTimeoutSec: 300,
   439  		Name:                      lb.ServiceName{Name: "svc3", Namespace: "ns3"},
   440  		LoadBalancerSourceRanges:  []*cidr.CIDR{cidr1},
   441  	}
   442  	created, id3, err := m.svc.UpsertService(p3)
   443  	if option.Config.EnableIPv6 {
   444  		require.Nil(t, err)
   445  		require.Equal(t, true, created)
   446  		require.Equal(t, lb.ID(3), id3)
   447  		require.Equal(t, 2, len(m.lbmap.ServiceByID[uint16(id3)].Backends))
   448  		require.Equal(t, 4, len(m.lbmap.BackendByID))
   449  		require.Equal(t, "svc3", m.svc.svcByID[id3].svcName.Name)
   450  		require.Equal(t, "ns3", m.svc.svcByID[id3].svcName.Namespace)
   451  		require.Equal(t, 2, len(m.lbmap.AffinityMatch[uint16(id3)]))
   452  		require.Equal(t, 1, len(m.lbmap.SourceRanges[uint16(id3)]))
   453  
   454  		// Should remove the IPv6 service
   455  		found, err := m.svc.DeleteServiceByID(lb.ServiceID(id3))
   456  		require.Nil(t, err)
   457  		require.Equal(t, true, found)
   458  	} else {
   459  		require.ErrorContains(t, err, "Unable to upsert service")
   460  		require.ErrorContains(t, err, "as IPv6 is disabled")
   461  		require.Equal(t, false, created)
   462  	}
   463  	require.Equal(t, 2, len(m.lbmap.ServiceByID))
   464  	require.Equal(t, 2, len(m.lbmap.BackendByID))
   465  
   466  	// Should remove the service and the backend, but keep another service and
   467  	// its backends. Also, should remove the affinity match.
   468  	found, err := m.svc.DeleteServiceByID(lb.ServiceID(id1))
   469  	require.Nil(t, err)
   470  	require.Equal(t, true, found)
   471  	require.Equal(t, 1, len(m.lbmap.ServiceByID))
   472  	require.Equal(t, 2, len(m.lbmap.BackendByID))
   473  	require.Equal(t, 0, len(m.lbmap.AffinityMatch[uint16(id1)]))
   474  
   475  	// Should delete both backends of service
   476  	p2.Backends = nil
   477  	p2.LoadBalancerSourceRanges = []*cidr.CIDR{cidr2}
   478  	created, id2, err = m.svc.UpsertService(p2)
   479  	require.Nil(t, err)
   480  	require.Equal(t, false, created)
   481  	require.Equal(t, lb.ID(2), id2)
   482  	require.Equal(t, 0, len(m.lbmap.ServiceByID[uint16(id2)].Backends))
   483  	require.Equal(t, 0, len(m.lbmap.BackendByID))
   484  	require.Equal(t, "svc2", m.svc.svcByID[id2].svcName.Name)
   485  	require.Equal(t, "ns2", m.svc.svcByID[id2].svcName.Namespace)
   486  	require.Equal(t, 0, len(m.lbmap.AffinityMatch[uint16(id2)]))
   487  	require.Equal(t, 1, len(m.lbmap.SourceRanges[uint16(id2)]))
   488  
   489  	// Should delete the remaining service
   490  	found, err = m.svc.DeleteServiceByID(lb.ServiceID(id2))
   491  	require.Nil(t, err)
   492  	require.Equal(t, true, found)
   493  	require.Equal(t, 0, len(m.lbmap.ServiceByID))
   494  	require.Equal(t, 0, len(m.lbmap.BackendByID))
   495  
   496  	// Should ignore the source range if it does not match FE's ip family
   497  	cidr1, err = cidr.ParseCIDR("fd00::/8")
   498  	require.Nil(t, err)
   499  	cidr2, err = cidr.ParseCIDR("192.168.1.0/24")
   500  	require.Nil(t, err)
   501  
   502  	p4 := &lb.SVC{
   503  		Frontend:                  frontend1,
   504  		Backends:                  backends1,
   505  		Type:                      lb.SVCTypeLoadBalancer,
   506  		ExtTrafficPolicy:          lb.SVCTrafficPolicyCluster,
   507  		IntTrafficPolicy:          lb.SVCTrafficPolicyCluster,
   508  		SessionAffinity:           true,
   509  		SessionAffinityTimeoutSec: 300,
   510  		Name:                      lb.ServiceName{Name: "svc3", Namespace: "ns3"},
   511  		LoadBalancerSourceRanges:  []*cidr.CIDR{cidr1, cidr2},
   512  	}
   513  	created, id4, err := m.svc.UpsertService(p4)
   514  	require.Equal(t, true, created)
   515  	require.Nil(t, err)
   516  	require.Equal(t, 1, len(m.lbmap.SourceRanges[uint16(id4)]))
   517  }
   518  
   519  func TestRestoreServices(t *testing.T) {
   520  	m := setupManagerTestSuite(t)
   521  
   522  	p1 := &lb.SVC{
   523  		Frontend:         frontend1,
   524  		Backends:         backends1,
   525  		Type:             lb.SVCTypeNodePort,
   526  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
   527  		IntTrafficPolicy: lb.SVCTrafficPolicyCluster,
   528  	}
   529  	_, id1, err := m.svc.UpsertService(p1)
   530  	require.Nil(t, err)
   531  	cidr1, err := cidr.ParseCIDR("10.0.0.0/8")
   532  	require.Nil(t, err)
   533  	cidr2, err := cidr.ParseCIDR("192.168.1.0/24")
   534  	require.Nil(t, err)
   535  	p2 := &lb.SVC{
   536  		Frontend:                  frontend2,
   537  		Backends:                  backends2,
   538  		Type:                      lb.SVCTypeLoadBalancer,
   539  		ExtTrafficPolicy:          lb.SVCTrafficPolicyCluster,
   540  		IntTrafficPolicy:          lb.SVCTrafficPolicyCluster,
   541  		SessionAffinity:           true,
   542  		SessionAffinityTimeoutSec: 200,
   543  		LoadBalancerSourceRanges:  []*cidr.CIDR{cidr1, cidr2},
   544  	}
   545  	_, id2, err := m.svc.UpsertService(p2)
   546  	require.Nil(t, err)
   547  
   548  	// Restart service, but keep the lbmap to restore services from
   549  	option.Config.NodePortAlg = option.NodePortAlgMaglev
   550  	option.Config.DatapathMode = datapathOpt.DatapathModeLBOnly
   551  	lbmap := m.svc.lbmap.(*mockmaps.LBMockMap)
   552  	m.newServiceMock(lbmap)
   553  
   554  	// Restore services from lbmap
   555  	err = m.svc.RestoreServices()
   556  	require.Nil(t, err)
   557  
   558  	// Backends have been restored
   559  	require.Equal(t, 3, len(m.svc.backendByHash))
   560  	backends := append(backends1, backends2...)
   561  	for _, b := range backends {
   562  		_, found := m.svc.backendByHash[b.Hash()]
   563  		require.Equal(t, true, found)
   564  	}
   565  
   566  	// Services have been restored too
   567  	require.Equal(t, 2, len(m.svc.svcByID))
   568  	require.EqualValues(t, lbmap.ServiceByID[uint16(id1)].Frontend, m.svc.svcByID[id1].frontend)
   569  	require.EqualValues(t, lbmap.ServiceByID[uint16(id1)].Backends, m.svc.svcByID[id1].backends)
   570  	require.EqualValues(t, lbmap.ServiceByID[uint16(id2)].Frontend, m.svc.svcByID[id2].frontend)
   571  	require.EqualValues(t, lbmap.ServiceByID[uint16(id2)].Backends, m.svc.svcByID[id2].backends)
   572  
   573  	// Session affinity too
   574  	require.Equal(t, false, m.svc.svcByID[id1].sessionAffinity)
   575  	require.Equal(t, true, m.svc.svcByID[id2].sessionAffinity)
   576  	require.Equal(t, uint32(200), m.svc.svcByID[id2].sessionAffinityTimeoutSec)
   577  
   578  	// LoadBalancer source ranges too
   579  	require.Equal(t, 2, len(m.svc.svcByID[id2].loadBalancerSourceRanges))
   580  	for _, cidr := range []*cidr.CIDR{cidr1, cidr2} {
   581  		found := false
   582  		for _, c := range m.svc.svcByID[id2].loadBalancerSourceRanges {
   583  			if c.String() == cidr.String() {
   584  				found = true
   585  				break
   586  			}
   587  		}
   588  		require.Equal(t, true, found)
   589  	}
   590  
   591  	// Maglev lookup table too
   592  	require.Equal(t, len(backends1), m.lbmap.DummyMaglevTable[uint16(id1)])
   593  	require.Equal(t, len(backends2), m.lbmap.DummyMaglevTable[uint16(id2)])
   594  }
   595  
   596  func TestSyncWithK8sFinished(t *testing.T) {
   597  	m := setupManagerTestSuite(t)
   598  
   599  	p1 := &lb.SVC{
   600  		Frontend:                  frontend1,
   601  		Backends:                  backends1,
   602  		Type:                      lb.SVCTypeNodePort,
   603  		ExtTrafficPolicy:          lb.SVCTrafficPolicyCluster,
   604  		IntTrafficPolicy:          lb.SVCTrafficPolicyCluster,
   605  		SessionAffinity:           true,
   606  		SessionAffinityTimeoutSec: 300,
   607  	}
   608  	_, id1, err := m.svc.UpsertService(p1)
   609  	require.Nil(t, err)
   610  	p2 := &lb.SVC{
   611  		Frontend:         frontend2,
   612  		Backends:         backends2,
   613  		Type:             lb.SVCTypeClusterIP,
   614  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
   615  		IntTrafficPolicy: lb.SVCTrafficPolicyCluster,
   616  		Name:             lb.ServiceName{Name: "svc2", Namespace: "ns2"},
   617  	}
   618  	_, _, err = m.svc.UpsertService(p2)
   619  	require.Nil(t, err)
   620  	require.Equal(t, 2, len(m.svc.svcByID))
   621  	require.Equal(t, 2, len(m.lbmap.AffinityMatch[uint16(id1)]))
   622  
   623  	// Restart service, but keep the lbmap to restore services from
   624  	lbmap := m.svc.lbmap.(*mockmaps.LBMockMap)
   625  	m.newServiceMock(lbmap)
   626  	err = m.svc.RestoreServices()
   627  	require.Nil(t, err)
   628  	require.Equal(t, 2, len(m.svc.svcByID))
   629  
   630  	// Imitate a situation where svc1 was deleted while we were down.
   631  	// In real life, the following upsert is called by k8s_watcher during
   632  	// the sync period of the cilium-agent's k8s service cache which happens
   633  	// during the initialization of cilium-agent. P2 svc updated affinity is synced.
   634  	p2.SessionAffinity = true
   635  	p2.SessionAffinityTimeoutSec = 100
   636  	_, id2, err := m.svc.UpsertService(p2)
   637  	require.Nil(t, err)
   638  
   639  	// Add non-existing affinity matches
   640  	lbmap.AddAffinityMatch(20, 300)
   641  	lbmap.AddAffinityMatch(20, 301)
   642  	lbmap.AddAffinityMatch(uint16(id1), 302)
   643  	lbmap.AddAffinityMatch(uint16(id2), 305)
   644  
   645  	// cilium-agent finished the initialization, and thus SyncWithK8sFinished
   646  	// is called
   647  	stale, err := m.svc.SyncWithK8sFinished(false, nil)
   648  	require.Nil(t, stale)
   649  	require.Nil(t, err)
   650  
   651  	// svc1 should be removed from cilium while svc2 is synced
   652  	require.Equal(t, 1, len(m.svc.svcByID))
   653  	_, found := m.svc.svcByID[id2]
   654  	require.Equal(t, true, found)
   655  	_, found = m.svc.svcByID[id1]
   656  	require.Equal(t, false, found)
   657  	require.Equal(t, "svc2", m.svc.svcByID[id2].svcName.Name)
   658  	require.Equal(t, "ns2", m.svc.svcByID[id2].svcName.Namespace)
   659  	require.Equal(t, 1, len(m.lbmap.AffinityMatch))
   660  	// Check that the non-existing affinity matches were removed
   661  	matches, _ := lbmap.DumpAffinityMatches()
   662  	require.Equal(t, 1, len(matches)) // id2 svc has updated session affinity
   663  	require.Equal(t, 2, len(matches[uint16(id2)]))
   664  	for _, b := range lbmap.ServiceByID[uint16(id2)].Backends {
   665  		require.Equal(t, struct{}{}, m.lbmap.AffinityMatch[uint16(id2)][b.ID])
   666  	}
   667  }
   668  
   669  func TestRestoreServiceWithStaleBackends(t *testing.T) {
   670  	backendAddrs := []string{"10.0.0.1", "10.0.0.2", "10.0.0.3", "10.0.0.4", "10.0.0.5"}
   671  	finalBackendAddrs := []string{"10.0.0.2", "10.0.0.3", "10.0.0.5"}
   672  
   673  	service := func(ns, name, frontend string, backends ...string) *lb.SVC {
   674  		var bes []*lb.Backend
   675  		for _, backend := range backends {
   676  			bes = append(bes, lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster(backend), 8080))
   677  		}
   678  
   679  		return &lb.SVC{
   680  			Frontend:         *lb.NewL3n4AddrID(lb.TCP, cmtypes.MustParseAddrCluster(frontend), 80, lb.ScopeExternal, 0),
   681  			Backends:         bes,
   682  			Type:             lb.SVCTypeClusterIP,
   683  			ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
   684  			IntTrafficPolicy: lb.SVCTrafficPolicyCluster,
   685  			Name:             lb.ServiceName{Name: name, Namespace: ns},
   686  		}
   687  	}
   688  
   689  	toBackendAddrs := func(backends []*lb.Backend) (addrs []string) {
   690  		for _, be := range backends {
   691  			addrs = append(addrs, be.L3n4Addr.AddrCluster.Addr().String())
   692  		}
   693  		return
   694  	}
   695  
   696  	tests := []struct {
   697  		name                string
   698  		localOnly           bool
   699  		isLocal             bool
   700  		expectStaleBackends bool
   701  	}{
   702  		{
   703  			name:                "local only, local service",
   704  			localOnly:           true,
   705  			isLocal:             true,
   706  			expectStaleBackends: false,
   707  		},
   708  		{
   709  			name:                "local only, global service",
   710  			localOnly:           true,
   711  			isLocal:             false,
   712  			expectStaleBackends: true,
   713  		},
   714  		{
   715  			name:                "all, local service",
   716  			localOnly:           false,
   717  			isLocal:             true,
   718  			expectStaleBackends: false,
   719  		},
   720  		{
   721  			name:                "all, global service",
   722  			localOnly:           false,
   723  			isLocal:             false,
   724  			expectStaleBackends: false,
   725  		},
   726  	}
   727  
   728  	for _, tt := range tests {
   729  		t.Run(tt.name, func(t *testing.T) {
   730  			lbmap := mockmaps.NewLBMockMap()
   731  			svc := newService(&FakeMonitorAgent{}, lbmap, nil)
   732  
   733  			_, id1, err := svc.upsertService(service("foo", "bar", "172.16.0.1", backendAddrs...))
   734  			require.NoError(t, err, "Failed to upsert service")
   735  
   736  			require.Contains(t, lbmap.ServiceByID, uint16(id1), "lbmap not populated correctly")
   737  			require.ElementsMatch(t, backendAddrs, toBackendAddrs(lbmap.ServiceByID[uint16(id1)].Backends), "lbmap not populated correctly")
   738  			require.ElementsMatch(t, backendAddrs, toBackendAddrs(maps.Values(lbmap.BackendByID)), "lbmap not populated correctly")
   739  
   740  			// Recreate the Service structure, but keep the lbmap to restore services from
   741  			svc = newService(&FakeMonitorAgent{}, lbmap, nil)
   742  			require.NoError(t, svc.RestoreServices(), "Failed to restore services")
   743  
   744  			// Simulate a set of service updates. Until synchronization completes, a given service
   745  			// might not yet contain all backends, in case they either belong to different endpointslices
   746  			// or different clusters.
   747  			_, id1bis, err := svc.upsertService(service("foo", "bar", "172.16.0.1", "10.0.0.3"))
   748  			require.NoError(t, err, "Failed to upsert service")
   749  			require.Equal(t, id1, id1bis, "Service ID changed unexpectedly")
   750  
   751  			// No backend should have been removed yet
   752  			require.Contains(t, lbmap.ServiceByID, uint16(id1), "lbmap incorrectly modified")
   753  			require.ElementsMatch(t, backendAddrs, toBackendAddrs(lbmap.ServiceByID[uint16(id1)].Backends), "lbmap incorrectly modified")
   754  			require.ElementsMatch(t, backendAddrs, toBackendAddrs(maps.Values(lbmap.BackendByID)), "lbmap incorrectly modified")
   755  
   756  			// Let's do it once more
   757  			_, id1ter, err := svc.upsertService(service("foo", "bar", "172.16.0.1", "10.0.0.2", "10.0.0.3", "10.0.0.5"))
   758  			require.NoError(t, err, "Failed to upsert service")
   759  			require.Equal(t, id1, id1ter, "Service ID changed unexpectedly")
   760  
   761  			// No backend should have been removed yet
   762  			require.Contains(t, lbmap.ServiceByID, uint16(id1), "lbmap incorrectly modified")
   763  			require.ElementsMatch(t, backendAddrs, toBackendAddrs(lbmap.ServiceByID[uint16(id1)].Backends), "lbmap incorrectly modified")
   764  			require.ElementsMatch(t, backendAddrs, toBackendAddrs(maps.Values(lbmap.BackendByID)), "lbmap incorrectly modified")
   765  
   766  			svcID := k8s.ServiceID{Namespace: "foo", Name: "bar"}
   767  			localServices := sets.New[k8s.ServiceID]()
   768  			if tt.isLocal {
   769  				localServices.Insert(svcID)
   770  			}
   771  
   772  			stale, err := svc.SyncWithK8sFinished(tt.localOnly, localServices)
   773  			require.NoError(t, err, "Failed to trigger garbage collection")
   774  
   775  			require.Contains(t, lbmap.ServiceByID, uint16(id1), "service incorrectly removed from lbmap")
   776  
   777  			// Stale backends should now have been removed (if appropriate)
   778  			if tt.expectStaleBackends {
   779  				require.Empty(t, stale)
   780  				require.ElementsMatch(t, backendAddrs, toBackendAddrs(lbmap.ServiceByID[uint16(id1)].Backends), "stale backends should not have been removed from lbmap")
   781  				require.ElementsMatch(t, backendAddrs, toBackendAddrs(maps.Values(lbmap.BackendByID)), "stale backends should not have been removed from lbmap")
   782  			} else {
   783  				require.ElementsMatch(t, stale, []k8s.ServiceID{svcID})
   784  
   785  				// Trigger a new upsertion: this mimics what would eventually happen when calling ServiceCache.EnsureService()
   786  				_, _, err := svc.upsertService(service("foo", "bar", "172.16.0.1", "10.0.0.2", "10.0.0.3", "10.0.0.5"))
   787  				require.NoError(t, err, "Failed to upsert service")
   788  
   789  				require.ElementsMatch(t, finalBackendAddrs, toBackendAddrs(lbmap.ServiceByID[uint16(id1)].Backends), "stale backends not correctly removed from lbmap")
   790  				require.ElementsMatch(t, finalBackendAddrs, toBackendAddrs(maps.Values(lbmap.BackendByID)), "stale backends not correctly removed from lbmap")
   791  			}
   792  		})
   793  	}
   794  }
   795  
   796  func TestHealthCheckNodePort(t *testing.T) {
   797  	m := setupManagerTestSuite(t)
   798  
   799  	// Create two frontends, one for LoadBalaner and one for ClusterIP.
   800  	// This is used to emulate how we get K8s services from the K8s watcher,
   801  	// i.e. one service per frontend (even if it is logically the same service)
   802  	loadBalancerIP := *lb.NewL3n4AddrID(lb.TCP, cmtypes.MustParseAddrCluster("1.1.1.1"), 80, lb.ScopeExternal, 0)
   803  	clusterIP := *lb.NewL3n4AddrID(lb.TCP, cmtypes.MustParseAddrCluster("10.20.30.40"), 80, lb.ScopeExternal, 0)
   804  
   805  	// Create two node-local backends
   806  	localBackend1 := lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.1"), 8080)
   807  	localBackend2 := lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.2"), 8080)
   808  	localTerminatingBackend3 := lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.3"), 8080)
   809  	localBackend1.NodeName = nodeTypes.GetName()
   810  	localBackend2.NodeName = nodeTypes.GetName()
   811  	localTerminatingBackend3.NodeName = nodeTypes.GetName()
   812  	localActiveBackends := []*lb.Backend{localBackend1, localBackend2}
   813  
   814  	// Create three remote backends
   815  	remoteBackend1 := lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.3"), 8080)
   816  	remoteBackend2 := lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.4"), 8080)
   817  	remoteBackend3 := lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.5"), 8080)
   818  	remoteBackend1.NodeName = "not-" + nodeTypes.GetName()
   819  	remoteBackend2.NodeName = "not-" + nodeTypes.GetName()
   820  	remoteBackend3.NodeName = "not-" + nodeTypes.GetName()
   821  	remoteBackends := []*lb.Backend{remoteBackend1, remoteBackend2, remoteBackend3}
   822  
   823  	allBackends := []*lb.Backend{localBackend1, localBackend2, localTerminatingBackend3, remoteBackend1, remoteBackend2, remoteBackend3}
   824  
   825  	// Insert svc1 as type LoadBalancer with some local backends
   826  	p1 := &lb.SVC{
   827  		Frontend:            loadBalancerIP,
   828  		Backends:            allBackends,
   829  		Type:                lb.SVCTypeLoadBalancer,
   830  		ExtTrafficPolicy:    lb.SVCTrafficPolicyLocal,
   831  		IntTrafficPolicy:    lb.SVCTrafficPolicyCluster,
   832  		HealthCheckNodePort: 32001,
   833  		Name:                lb.ServiceName{Name: "svc1", Namespace: "ns1"},
   834  	}
   835  	_, id1, err := m.svc.UpsertService(p1)
   836  	require.Nil(t, err)
   837  	require.Equal(t, "svc1", m.svcHealth.ServiceByPort(32001).Service.Name)
   838  	require.Equal(t, "ns1", m.svcHealth.ServiceByPort(32001).Service.Namespace)
   839  
   840  	p1.Backends[2].State = lb.BackendStateTerminating
   841  	_, _, _ = m.svc.UpsertService(p1)
   842  	require.Equal(t, len(localActiveBackends), m.svcHealth.ServiceByPort(32001).LocalEndpoints)
   843  
   844  	// Insert the ClusterIP frontend of svc1
   845  	p2 := &lb.SVC{
   846  		Frontend:            clusterIP,
   847  		Backends:            allBackends,
   848  		Type:                lb.SVCTypeClusterIP,
   849  		ExtTrafficPolicy:    lb.SVCTrafficPolicyLocal,
   850  		IntTrafficPolicy:    lb.SVCTrafficPolicyCluster,
   851  		HealthCheckNodePort: 32001,
   852  		Name:                lb.ServiceName{Name: "svc1", Namespace: "ns1"},
   853  	}
   854  	_, id2, err := m.svc.UpsertService(p2)
   855  	require.Nil(t, err)
   856  	require.Equal(t, "svc1", m.svcHealth.ServiceByPort(32001).Service.Name)
   857  	require.Equal(t, "ns1", m.svcHealth.ServiceByPort(32001).Service.Namespace)
   858  	require.Equal(t, len(localActiveBackends), m.svcHealth.ServiceByPort(32001).LocalEndpoints)
   859  
   860  	// Update the HealthCheckNodePort for svc1
   861  	p1.HealthCheckNodePort = 32000
   862  	new, _, err := m.svc.UpsertService(p1)
   863  	require.Nil(t, err)
   864  	require.Equal(t, false, new)
   865  	require.Equal(t, "svc1", m.svcHealth.ServiceByPort(32000).Service.Name)
   866  	require.Equal(t, "ns1", m.svcHealth.ServiceByPort(32000).Service.Namespace)
   867  	require.Equal(t, len(localActiveBackends), m.svcHealth.ServiceByPort(32000).LocalEndpoints)
   868  	require.Nil(t, m.svcHealth.ServiceByPort(32001))
   869  
   870  	// Update the externalTrafficPolicy for svc1
   871  	p1.ExtTrafficPolicy = lb.SVCTrafficPolicyCluster
   872  	p1.HealthCheckNodePort = 0
   873  	new, _, err = m.svc.UpsertService(p1)
   874  	require.Nil(t, err)
   875  	require.Equal(t, false, new)
   876  	require.Nil(t, m.svcHealth.ServiceByPort(32000))
   877  	require.Nil(t, m.svcHealth.ServiceByPort(32001))
   878  
   879  	// Restore the original version of svc1
   880  	p1.ExtTrafficPolicy = lb.SVCTrafficPolicyLocal
   881  	p1.HealthCheckNodePort = 32001
   882  	new, _, err = m.svc.UpsertService(p1)
   883  	require.Nil(t, err)
   884  	require.Equal(t, false, new)
   885  	require.Equal(t, "svc1", m.svcHealth.ServiceByPort(32001).Service.Name)
   886  	require.Equal(t, "ns1", m.svcHealth.ServiceByPort(32001).Service.Namespace)
   887  	require.Equal(t, len(localActiveBackends), m.svcHealth.ServiceByPort(32001).LocalEndpoints)
   888  
   889  	// Upsert svc1 of type LoadBalancer with only remote backends
   890  	p1.Backends = remoteBackends
   891  	new, _, err = m.svc.UpsertService(p1)
   892  	require.Nil(t, err)
   893  	require.Equal(t, false, new)
   894  	require.Equal(t, "svc1", m.svcHealth.ServiceByPort(32001).Service.Name)
   895  	require.Equal(t, "ns1", m.svcHealth.ServiceByPort(32001).Service.Namespace)
   896  	require.Equal(t, 0, m.svcHealth.ServiceByPort(32001).LocalEndpoints)
   897  
   898  	// Upsert svc1 of type ClusterIP with only remote backends
   899  	p2.Backends = remoteBackends
   900  	new, _, err = m.svc.UpsertService(p2)
   901  	require.Nil(t, err)
   902  	require.Equal(t, false, new)
   903  	require.Equal(t, "svc1", m.svcHealth.ServiceByPort(32001).Service.Name)
   904  	require.Equal(t, "ns1", m.svcHealth.ServiceByPort(32001).Service.Namespace)
   905  	require.Equal(t, 0, m.svcHealth.ServiceByPort(32001).LocalEndpoints)
   906  
   907  	// Delete svc1 of type LoadBalancer
   908  	found, err := m.svc.DeleteServiceByID(lb.ServiceID(id1))
   909  	require.Nil(t, err)
   910  	require.Equal(t, true, found)
   911  	require.Nil(t, m.svcHealth.ServiceByPort(32001))
   912  
   913  	// Delete svc1 of type ClusterIP
   914  	found, err = m.svc.DeleteServiceByID(lb.ServiceID(id2))
   915  	require.Nil(t, err)
   916  	require.Equal(t, true, found)
   917  	require.Nil(t, m.svcHealth.ServiceByPort(32001))
   918  }
   919  
   920  // Define a mock implementation of the NodeMetaCollector interface for testing
   921  type mockNodeMetaCollector struct {
   922  	ipv4 net.IP
   923  	ipv6 net.IP
   924  }
   925  
   926  func (m *mockNodeMetaCollector) GetIPv4() net.IP {
   927  	return m.ipv4
   928  }
   929  
   930  func (m *mockNodeMetaCollector) GetIPv6() net.IP {
   931  	return m.ipv6
   932  }
   933  
   934  func TestHealthCheckLoadBalancerIP(t *testing.T) {
   935  	m := setupManagerTestSuite(t)
   936  
   937  	option.Config.EnableHealthCheckLoadBalancerIP = true
   938  
   939  	mockCollector := &mockNodeMetaCollector{
   940  		ipv4: net.ParseIP("192.0.2.0"),
   941  		ipv6: net.ParseIP("2001:db8::1"),
   942  	}
   943  
   944  	loadBalancerIP := *lb.NewL3n4AddrID(lb.TCP, cmtypes.MustParseAddrCluster("1.1.1.1"), 80, lb.ScopeExternal, 0)
   945  
   946  	localBackend1 := lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.1"), 8080)
   947  	localBackend1.NodeName = nodeTypes.GetName()
   948  
   949  	allBackends := []*lb.Backend{localBackend1}
   950  
   951  	// Insert svc1 as type LoadBalancer with some local backends
   952  	p1 := &lb.SVC{
   953  		Frontend:            loadBalancerIP,
   954  		Backends:            allBackends,
   955  		Type:                lb.SVCTypeLoadBalancer,
   956  		ExtTrafficPolicy:    lb.SVCTrafficPolicyLocal,
   957  		IntTrafficPolicy:    lb.SVCTrafficPolicyCluster,
   958  		HealthCheckNodePort: 32001,
   959  		Name:                lb.ServiceName{Name: "svc1", Namespace: "ns1"},
   960  	}
   961  
   962  	svc, _, _, _, _ := m.svc.createSVCInfoIfNotExist(p1)
   963  	err := m.svc.upsertNodePortHealthService(svc, mockCollector)
   964  
   965  	require.Nil(t, err)
   966  	require.NotEqual(t, "", svc.healthcheckFrontendHash)
   967  	require.Equal(t, "svc1-healthCheck", m.svc.svcByHash[svc.healthcheckFrontendHash].svcName.Name)
   968  	require.Equal(t, "ns1", m.svc.svcByHash[svc.healthcheckFrontendHash].svcName.Namespace)
   969  	require.Equal(t, svc.svcHealthCheckNodePort, m.svc.svcByHash[svc.healthcheckFrontendHash].frontend.Port)
   970  	require.Equal(t, netip.MustParseAddr("1.1.1.1"), m.svc.svcByHash[svc.healthcheckFrontendHash].frontend.AddrCluster.Addr())
   971  	require.Equal(t, cmtypes.AddrClusterFrom(netip.MustParseAddr("192.0.2.0"), option.Config.ClusterID), m.svc.svcByHash[svc.healthcheckFrontendHash].backends[0].AddrCluster)
   972  
   973  	// Update the externalTrafficPolicy for svc1
   974  	svc.frontend.Scope = lb.ScopeExternal
   975  	svc.svcHealthCheckNodePort = 0
   976  	oldHealthHash := svc.healthcheckFrontendHash
   977  	err = m.svc.upsertNodePortHealthService(svc, mockCollector)
   978  	require.Nil(t, err)
   979  	require.Equal(t, "", svc.healthcheckFrontendHash)
   980  	require.Nil(t, m.svc.svcByHash[oldHealthHash])
   981  
   982  	// Restore the original version of svc1
   983  	svc.frontend.Scope = lb.ScopeInternal
   984  	svc.svcHealthCheckNodePort = 32001
   985  	err = m.svc.upsertNodePortHealthService(svc, mockCollector)
   986  	require.Nil(t, err)
   987  	require.NotEqual(t, "", svc.healthcheckFrontendHash)
   988  	require.Equal(t, "svc1-healthCheck", m.svc.svcByHash[svc.healthcheckFrontendHash].svcName.Name)
   989  	require.Equal(t, "ns1", m.svc.svcByHash[svc.healthcheckFrontendHash].svcName.Namespace)
   990  	require.Equal(t, svc.svcHealthCheckNodePort, m.svc.svcByHash[svc.healthcheckFrontendHash].frontend.Port)
   991  	require.Equal(t, netip.MustParseAddr("1.1.1.1"), m.svc.svcByHash[svc.healthcheckFrontendHash].frontend.AddrCluster.Addr())
   992  	require.Equal(t, cmtypes.AddrClusterFrom(netip.MustParseAddr("192.0.2.0"), option.Config.ClusterID), m.svc.svcByHash[svc.healthcheckFrontendHash].backends[0].AddrCluster)
   993  
   994  	// IPv6 NodePort Backend
   995  	oldHealthHash = svc.healthcheckFrontendHash
   996  	svc.frontend = *lb.NewL3n4AddrID(lb.TCP, cmtypes.MustParseAddrCluster("2001:db8:1::1"), 80, lb.ScopeExternal, 0)
   997  	err = m.svc.upsertNodePortHealthService(svc, mockCollector)
   998  	require.Nil(t, err)
   999  	require.Equal(t, cmtypes.AddrClusterFrom(netip.MustParseAddr("2001:db8::1"), option.Config.ClusterID), m.svc.svcByHash[svc.healthcheckFrontendHash].backends[0].AddrCluster)
  1000  	require.Nil(t, m.svc.svcByHash[oldHealthHash])
  1001  
  1002  	var ok bool
  1003  	// Delete
  1004  	ok, err = m.svc.DeleteService(m.svc.svcByHash[svc.healthcheckFrontendHash].frontend.L3n4Addr)
  1005  	require.Equal(t, true, ok)
  1006  	require.Nil(t, err)
  1007  
  1008  	option.Config.EnableHealthCheckLoadBalancerIP = false
  1009  }
  1010  
  1011  func TestHealthCheckNodePortDisabled(t *testing.T) {
  1012  	m := setupManagerTestSuite(t)
  1013  
  1014  	// NewService sets healthServer to nil if EnableHealthCheckNodePort is
  1015  	// false at start time. We emulate this here by temporarily setting it nil.
  1016  	enableHealthCheckNodePort := option.Config.EnableHealthCheckNodePort
  1017  	healthServer := m.svc.healthServer
  1018  	option.Config.EnableHealthCheckNodePort = false
  1019  	m.svc.healthServer = nil
  1020  	defer func() {
  1021  		option.Config.EnableHealthCheckNodePort = enableHealthCheckNodePort
  1022  		m.svc.healthServer = healthServer
  1023  	}()
  1024  
  1025  	p1 := &lb.SVC{
  1026  		Frontend:            frontend1,
  1027  		Backends:            backends1,
  1028  		Type:                lb.SVCTypeNodePort,
  1029  		ExtTrafficPolicy:    lb.SVCTrafficPolicyLocal,
  1030  		IntTrafficPolicy:    lb.SVCTrafficPolicyCluster,
  1031  		HealthCheckNodePort: 32000,
  1032  	}
  1033  	_, id1, err := m.svc.UpsertService(p1)
  1034  	require.Nil(t, err)
  1035  
  1036  	// Unset HealthCheckNodePort for that service
  1037  	p1.HealthCheckNodePort = 0
  1038  	p1.ExtTrafficPolicy = lb.SVCTrafficPolicyCluster
  1039  	_, _, err = m.svc.UpsertService(p1)
  1040  	require.Nil(t, err)
  1041  
  1042  	// Set HealthCheckNodePort for that service
  1043  	p1.HealthCheckNodePort = 32000
  1044  	p1.ExtTrafficPolicy = lb.SVCTrafficPolicyLocal
  1045  	_, _, err = m.svc.UpsertService(p1)
  1046  	require.Nil(t, err)
  1047  
  1048  	// Delete service with active HealthCheckNodePort
  1049  	found, err := m.svc.DeleteServiceByID(lb.ServiceID(id1))
  1050  	require.Nil(t, err)
  1051  	require.Equal(t, true, found)
  1052  }
  1053  
  1054  func TestGetServiceNameByAddr(t *testing.T) {
  1055  	m := setupManagerTestSuite(t)
  1056  
  1057  	fe := frontend1.DeepCopy()
  1058  	name := "svc1"
  1059  	namespace := "ns1"
  1060  	hcport := uint16(3)
  1061  	p := &lb.SVC{
  1062  		Frontend:            *fe,
  1063  		Backends:            backends1,
  1064  		Type:                lb.SVCTypeNodePort,
  1065  		ExtTrafficPolicy:    lb.SVCTrafficPolicyCluster,
  1066  		IntTrafficPolicy:    lb.SVCTrafficPolicyCluster,
  1067  		HealthCheckNodePort: hcport,
  1068  		Name:                lb.ServiceName{Name: name, Namespace: namespace},
  1069  	}
  1070  	created, id1, err := m.svc.UpsertService(p)
  1071  	require.Nil(t, err)
  1072  	require.Equal(t, true, created)
  1073  	require.Equal(t, lb.ID(1), id1)
  1074  	fe.ID = id1
  1075  	gotNamespace, gotName, ok := m.svc.GetServiceNameByAddr(frontend1.L3n4Addr)
  1076  	require.Equal(t, namespace, gotNamespace)
  1077  	require.Equal(t, name, gotName)
  1078  	require.Equal(t, true, ok)
  1079  	_, _, ok = m.svc.GetServiceNameByAddr(frontend2.L3n4Addr)
  1080  	require.Equal(t, false, ok)
  1081  }
  1082  
  1083  func TestLocalRedirectLocalBackendSelection(t *testing.T) {
  1084  	m := setupManagerTestSuite(t)
  1085  
  1086  	// Create a node-local backend.
  1087  	localBackend := backends1[0]
  1088  	localBackend.NodeName = nodeTypes.GetName()
  1089  	localBackends := []*lb.Backend{localBackend}
  1090  	// Create two remote backends.
  1091  	remoteBackends := make([]*lb.Backend, 0, len(backends2))
  1092  	for _, backend := range backends2 {
  1093  		backend.NodeName = "not-" + nodeTypes.GetName()
  1094  		remoteBackends = append(remoteBackends, backend)
  1095  	}
  1096  	allBackends := make([]*lb.Backend, 0, 1+len(remoteBackends))
  1097  	allBackends = append(allBackends, localBackend)
  1098  	allBackends = append(allBackends, remoteBackends...)
  1099  
  1100  	// Create a service entry of type Local Redirect.
  1101  	p1 := &lb.SVC{
  1102  		Frontend:         frontend1,
  1103  		Backends:         allBackends,
  1104  		Type:             lb.SVCTypeLocalRedirect,
  1105  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1106  		IntTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1107  		Name:             lb.ServiceName{Name: "svc1", Namespace: "ns1"},
  1108  	}
  1109  	// Insert the service entry of type Local Redirect.
  1110  	created, id, err := m.svc.UpsertService(p1)
  1111  	require.Nil(t, err)
  1112  	require.Equal(t, true, created)
  1113  	require.NotEqual(t, lb.ID(0), id)
  1114  
  1115  	svc, ok := m.svc.svcByID[id]
  1116  	require.Equal(t, true, ok)
  1117  	require.Equal(t, "ns1", svc.svcName.Namespace)
  1118  	require.Equal(t, "svc1", svc.svcName.Name)
  1119  	// Only node-local backends are selected
  1120  	require.Equal(t, len(localBackends), len(svc.backends))
  1121  
  1122  	svcFromLbMap, ok := m.lbmap.ServiceByID[uint16(id)]
  1123  	require.Equal(t, true, ok)
  1124  	require.Equal(t, len(svc.backends), len(svcFromLbMap.Backends))
  1125  }
  1126  
  1127  // Local redirect service should be able to override a ClusterIP service with same
  1128  // frontend, but reverse should produce an error. Also, it should not override
  1129  // any other type besides itself or clusterIP type.
  1130  func TestLocalRedirectServiceOverride(t *testing.T) {
  1131  	m := setupManagerTestSuite(t)
  1132  
  1133  	// Create a node-local backend.
  1134  	localBackend := backends1[0]
  1135  	localBackend.NodeName = nodeTypes.GetName()
  1136  	localBackends := []*lb.Backend{localBackend}
  1137  	// Create two remote backends.
  1138  	remoteBackends := make([]*lb.Backend, 0, len(backends2))
  1139  	for _, backend := range backends2 {
  1140  		backend.NodeName = "not-" + nodeTypes.GetName()
  1141  		remoteBackends = append(remoteBackends, backend)
  1142  	}
  1143  	allBackends := make([]*lb.Backend, 0, 1+len(remoteBackends))
  1144  	allBackends = append(allBackends, localBackend)
  1145  	allBackends = append(allBackends, remoteBackends...)
  1146  
  1147  	p1 := &lb.SVC{
  1148  		Frontend:         frontend1,
  1149  		Backends:         allBackends,
  1150  		Type:             lb.SVCTypeClusterIP,
  1151  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1152  		IntTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1153  		Name:             lb.ServiceName{Name: "svc1", Namespace: "ns1"},
  1154  	}
  1155  
  1156  	// Insert the service entry of type ClusterIP.
  1157  	created, id, err := m.svc.UpsertService(p1)
  1158  	require.Nil(t, err)
  1159  	require.Equal(t, true, created)
  1160  	require.NotEqual(t, lb.ID(0), id)
  1161  
  1162  	svc, ok := m.svc.svcByID[id]
  1163  	require.Equal(t, len(allBackends), len(svc.backends))
  1164  	require.Equal(t, true, ok)
  1165  
  1166  	// Insert the service entry of type Local Redirect.
  1167  	p1.Type = lb.SVCTypeLocalRedirect
  1168  	created, id, err = m.svc.UpsertService(p1)
  1169  
  1170  	// Local redirect service should override the ClusterIP service with node-local backends.
  1171  	require.Nil(t, err)
  1172  	require.Equal(t, false, created)
  1173  	require.NotEqual(t, lb.ID(0), id)
  1174  	svc = m.svc.svcByID[id]
  1175  	// Only node-local backends are selected.
  1176  	require.Equal(t, len(localBackends), len(svc.backends))
  1177  
  1178  	// Insert the service entry of type ClusterIP.
  1179  	p1.Type = lb.SVCTypeClusterIP
  1180  	created, _, err = m.svc.UpsertService(p1)
  1181  
  1182  	require.Error(t, err)
  1183  	require.Equal(t, false, created)
  1184  
  1185  	p2 := &lb.SVC{
  1186  		Frontend:         frontend2,
  1187  		Backends:         allBackends,
  1188  		Type:             lb.SVCTypeNodePort,
  1189  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1190  		IntTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1191  		Name:             lb.ServiceName{Name: "svc2", Namespace: "ns1"},
  1192  	}
  1193  
  1194  	// Insert the service entry of type NodePort.
  1195  	created, id, err = m.svc.UpsertService(p2)
  1196  	require.Nil(t, err)
  1197  	require.Equal(t, true, created)
  1198  	require.NotEqual(t, lb.ID(0), id)
  1199  
  1200  	svc, ok = m.svc.svcByID[id]
  1201  	require.Equal(t, len(allBackends), len(svc.backends))
  1202  	require.Equal(t, true, ok)
  1203  
  1204  	// Insert the service entry of type Local Redirect.
  1205  	p2.Type = lb.SVCTypeLocalRedirect
  1206  	created, _, err = m.svc.UpsertService(p2)
  1207  
  1208  	// Local redirect service should not override the NodePort service.
  1209  	require.Error(t, err)
  1210  	require.Equal(t, false, created)
  1211  }
  1212  
  1213  // Tests whether upsert service handles terminating backends, whereby terminating
  1214  // backends are not added to the service map, but are added to the backends and
  1215  // affinity maps.
  1216  func TestUpsertServiceWithTerminatingBackends(t *testing.T) {
  1217  	m := setupManagerTestSuite(t)
  1218  
  1219  	option.Config.NodePortAlg = option.NodePortAlgMaglev
  1220  	backends := append(backends4, backends1...)
  1221  	p := &lb.SVC{
  1222  		Frontend:                  frontend1,
  1223  		Backends:                  backends,
  1224  		Type:                      lb.SVCTypeNodePort,
  1225  		ExtTrafficPolicy:          lb.SVCTrafficPolicyCluster,
  1226  		IntTrafficPolicy:          lb.SVCTrafficPolicyCluster,
  1227  		SessionAffinity:           true,
  1228  		SessionAffinityTimeoutSec: 100,
  1229  		Name:                      lb.ServiceName{Name: "svc1", Namespace: "ns1"},
  1230  	}
  1231  
  1232  	created, id1, err := m.svc.UpsertService(p)
  1233  
  1234  	require.Nil(t, err)
  1235  	require.Equal(t, true, created)
  1236  	require.Equal(t, lb.ID(1), id1)
  1237  	require.Equal(t, len(backends), len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1238  	require.Equal(t, len(backends), m.lbmap.SvcActiveBackendsCount[uint16(id1)])
  1239  
  1240  	p.Backends[0].State = lb.BackendStateTerminating
  1241  
  1242  	_, _, err = m.svc.UpsertService(p)
  1243  
  1244  	require.Nil(t, err)
  1245  	require.Equal(t, len(backends), len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1246  	require.Equal(t, len(backends1), m.lbmap.SvcActiveBackendsCount[uint16(id1)])
  1247  	// Sorted active backends by ID first followed by non-active
  1248  	require.Equal(t, lb.BackendID(2), m.lbmap.ServiceByID[uint16(id1)].Backends[0].ID)
  1249  	require.Equal(t, lb.BackendID(3), m.lbmap.ServiceByID[uint16(id1)].Backends[1].ID)
  1250  	require.Equal(t, lb.BackendID(1), m.lbmap.ServiceByID[uint16(id1)].Backends[2].ID)
  1251  	require.Equal(t, 3, len(m.lbmap.BackendByID))
  1252  	require.Equal(t, "svc1", m.svc.svcByID[id1].svcName.Name)
  1253  	require.Equal(t, "ns1", m.svc.svcByID[id1].svcName.Namespace)
  1254  	require.Equal(t, 3, len(m.lbmap.AffinityMatch[uint16(id1)]))
  1255  	for bID := range m.lbmap.BackendByID {
  1256  		require.Equal(t, struct{}{}, m.lbmap.AffinityMatch[uint16(id1)][bID])
  1257  	}
  1258  	require.Equal(t, len(backends1), m.lbmap.DummyMaglevTable[uint16(id1)])
  1259  
  1260  	// Delete terminating backends.
  1261  	p.Backends = []*lb.Backend{}
  1262  
  1263  	created, id1, err = m.svc.UpsertService(p)
  1264  
  1265  	require.Nil(t, err)
  1266  	require.Equal(t, false, created)
  1267  	require.Equal(t, lb.ID(1), id1)
  1268  	require.Equal(t, 0, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1269  	require.Equal(t, 0, len(m.lbmap.BackendByID))
  1270  	require.Equal(t, "svc1", m.svc.svcByID[id1].svcName.Name)
  1271  	require.Equal(t, "ns1", m.svc.svcByID[id1].svcName.Namespace)
  1272  	require.Equal(t, 0, len(m.lbmap.AffinityMatch[uint16(id1)]))
  1273  }
  1274  
  1275  // TestUpsertServiceWithOnlyTerminatingBackends tests that a terminating backend is still
  1276  // used if there are not active backends.
  1277  func TestUpsertServiceWithOnlyTerminatingBackends(t *testing.T) {
  1278  	m := setupManagerTestSuite(t)
  1279  
  1280  	option.Config.NodePortAlg = option.NodePortAlgMaglev
  1281  	backends := backends1 // There are 2 backends
  1282  	p := &lb.SVC{
  1283  		Frontend:                  frontend1,
  1284  		Backends:                  backends,
  1285  		Type:                      lb.SVCTypeNodePort,
  1286  		ExtTrafficPolicy:          lb.SVCTrafficPolicyCluster,
  1287  		IntTrafficPolicy:          lb.SVCTrafficPolicyCluster,
  1288  		SessionAffinity:           true,
  1289  		SessionAffinityTimeoutSec: 100,
  1290  		Name:                      lb.ServiceName{Name: "svc1", Namespace: "ns1"},
  1291  	}
  1292  
  1293  	created, id1, err := m.svc.UpsertService(p)
  1294  
  1295  	require.Nil(t, err)
  1296  	require.Equal(t, true, created)
  1297  	require.Equal(t, lb.ID(1), id1)
  1298  	require.Equal(t, 2, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1299  	require.Equal(t, 2, m.lbmap.SvcActiveBackendsCount[uint16(id1)])
  1300  	require.Equal(t, "svc1", m.svc.svcByID[id1].svcName.Name)
  1301  	require.Equal(t, "ns1", m.svc.svcByID[id1].svcName.Namespace)
  1302  
  1303  	// The terminating backend should not be considered
  1304  	p.Backends[1].State = lb.BackendStateTerminating
  1305  
  1306  	created, id1, err = m.svc.UpsertService(p)
  1307  
  1308  	require.Nil(t, err)
  1309  	require.Equal(t, false, created)
  1310  	require.Equal(t, lb.ID(1), id1)
  1311  	require.Equal(t, 2, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1312  	require.Equal(t, 2, len(m.lbmap.BackendByID))
  1313  	require.Equal(t, 1, m.lbmap.SvcActiveBackendsCount[uint16(id1)])
  1314  
  1315  	// Delete terminating backends.
  1316  	p.Backends = p.Backends[:1]
  1317  
  1318  	created, id1, err = m.svc.UpsertService(p)
  1319  
  1320  	require.Nil(t, err)
  1321  	require.Equal(t, false, created)
  1322  	require.Equal(t, lb.ID(1), id1)
  1323  	require.Equal(t, 1, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1324  	require.Equal(t, 1, len(m.lbmap.BackendByID))
  1325  	require.Equal(t, 1, len(m.lbmap.AffinityMatch[uint16(id1)]))
  1326  
  1327  	// The terminating backend should be considered since there are no more active
  1328  	p.Backends[0].State = lb.BackendStateTerminating
  1329  
  1330  	created, id1, err = m.svc.UpsertService(p)
  1331  
  1332  	require.Nil(t, err)
  1333  	require.Equal(t, false, created)
  1334  	require.Equal(t, lb.ID(1), id1)
  1335  	require.Equal(t, 1, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1336  	require.Equal(t, 1, len(m.lbmap.BackendByID))
  1337  	require.Equal(t, 0, m.lbmap.SvcActiveBackendsCount[uint16(id1)])
  1338  
  1339  	// Delete terminating backends.
  1340  	p.Backends = []*lb.Backend{}
  1341  
  1342  	created, id1, err = m.svc.UpsertService(p)
  1343  
  1344  	require.Nil(t, err)
  1345  	require.Equal(t, false, created)
  1346  	require.Equal(t, lb.ID(1), id1)
  1347  	require.Equal(t, 0, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1348  	require.Equal(t, 0, len(m.lbmap.BackendByID))
  1349  	require.Equal(t, "svc1", m.svc.svcByID[id1].svcName.Name)
  1350  	require.Equal(t, "ns1", m.svc.svcByID[id1].svcName.Namespace)
  1351  	require.Equal(t, 0, len(m.lbmap.AffinityMatch[uint16(id1)]))
  1352  }
  1353  
  1354  // Tests whether upsert service provisions the Maglev LUT for ClusterIP,
  1355  // if ExternalClusterIP is true
  1356  func TestUpsertServiceWithExternalClusterIP(t *testing.T) {
  1357  	m := setupManagerTestSuite(t)
  1358  
  1359  	option.Config.NodePortAlg = option.NodePortAlgMaglev
  1360  	option.Config.ExternalClusterIP = true
  1361  	backends := make([]*lb.Backend, 0, len(backends1))
  1362  	for _, b := range backends1 {
  1363  		backends = append(backends, b.DeepCopy())
  1364  	}
  1365  	backends[0].State = lb.BackendStateActive
  1366  	backends[1].State = lb.BackendStateActive
  1367  	p := &lb.SVC{
  1368  		Frontend:         frontend1,
  1369  		Backends:         backends,
  1370  		Type:             lb.SVCTypeClusterIP,
  1371  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1372  		IntTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1373  		Name:             lb.ServiceName{Name: "svc1", Namespace: "ns1"},
  1374  	}
  1375  
  1376  	created, id1, err := m.svc.UpsertService(p)
  1377  
  1378  	require.Nil(t, err)
  1379  	require.Equal(t, true, created)
  1380  	require.Equal(t, lb.ID(1), id1)
  1381  	require.Equal(t, 2, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1382  	require.Equal(t, 2, len(m.lbmap.BackendByID))
  1383  	require.Equal(t, "svc1", m.svc.svcByID[id1].svcName.Name)
  1384  	require.Equal(t, "ns1", m.svc.svcByID[id1].svcName.Namespace)
  1385  	require.Equal(t, len(backends), m.lbmap.DummyMaglevTable[uint16(id1)])
  1386  }
  1387  
  1388  // Tests whether upsert service doesn't provision the Maglev LUT for ClusterIP,
  1389  // if ExternalClusterIP is false
  1390  func TestUpsertServiceWithOutExternalClusterIP(t *testing.T) {
  1391  	m := setupManagerTestSuite(t)
  1392  
  1393  	option.Config.NodePortAlg = option.NodePortAlgMaglev
  1394  	p := &lb.SVC{
  1395  		Frontend:         frontend1,
  1396  		Backends:         backends1,
  1397  		Type:             lb.SVCTypeClusterIP,
  1398  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1399  		IntTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1400  		Name:             lb.ServiceName{Name: "svc1", Namespace: "ns1"},
  1401  	}
  1402  
  1403  	created, id1, err := m.svc.UpsertService(p)
  1404  
  1405  	require.Nil(t, err)
  1406  	require.Equal(t, true, created)
  1407  	require.Equal(t, lb.ID(1), id1)
  1408  	require.Equal(t, 2, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1409  	require.Equal(t, 2, len(m.lbmap.BackendByID))
  1410  	require.Equal(t, "svc1", m.svc.svcByID[id1].svcName.Name)
  1411  	require.Equal(t, "ns1", m.svc.svcByID[id1].svcName.Namespace)
  1412  	require.Equal(t, 0, m.lbmap.DummyMaglevTable[uint16(id1)])
  1413  }
  1414  
  1415  // Tests terminating backend entries are not removed after service restore.
  1416  func TestRestoreServiceWithTerminatingBackends(t *testing.T) {
  1417  	m := setupManagerTestSuite(t)
  1418  
  1419  	option.Config.NodePortAlg = option.NodePortAlgMaglev
  1420  	backends := append(backends4, backends1...)
  1421  	p := &lb.SVC{
  1422  		Frontend:                  frontend1,
  1423  		Backends:                  backends,
  1424  		Type:                      lb.SVCTypeNodePort,
  1425  		ExtTrafficPolicy:          lb.SVCTrafficPolicyCluster,
  1426  		IntTrafficPolicy:          lb.SVCTrafficPolicyCluster,
  1427  		SessionAffinity:           true,
  1428  		SessionAffinityTimeoutSec: 100,
  1429  		Name:                      lb.ServiceName{Name: "svc1", Namespace: "ns1"},
  1430  	}
  1431  
  1432  	created, id1, err := m.svc.UpsertService(p)
  1433  
  1434  	t.Log(m.lbmap.ServiceByID[0])
  1435  	require.Nil(t, err)
  1436  	require.Equal(t, true, created)
  1437  	require.Equal(t, lb.ID(1), id1)
  1438  	require.Equal(t, len(backends), len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1439  	require.Equal(t, len(backends), m.lbmap.SvcActiveBackendsCount[uint16(id1)])
  1440  
  1441  	p.Backends[0].State = lb.BackendStateTerminating
  1442  
  1443  	_, _, err = m.svc.UpsertService(p)
  1444  
  1445  	require.Nil(t, err)
  1446  
  1447  	// Simulate agent restart.
  1448  	lbmap := m.svc.lbmap.(*mockmaps.LBMockMap)
  1449  	m.newServiceMock(lbmap)
  1450  
  1451  	// Restore services from lbmap
  1452  	err = m.svc.RestoreServices()
  1453  	require.Nil(t, err)
  1454  
  1455  	// Backends including terminating ones have been restored
  1456  	require.Equal(t, 3, len(m.svc.backendByHash))
  1457  	for _, b := range backends1 {
  1458  		_, found := m.svc.backendByHash[b.Hash()]
  1459  		require.Equal(t, true, found)
  1460  	}
  1461  
  1462  	// Affinity matches including terminating ones were restored
  1463  	matches, _ := m.lbmap.DumpAffinityMatches()
  1464  	require.Equal(t, 1, len(matches))
  1465  	require.Equal(t, 3, len(matches[uint16(id1)]))
  1466  	for _, b := range m.lbmap.ServiceByID[uint16(id1)].Backends {
  1467  		require.Equal(t, struct{}{}, m.lbmap.AffinityMatch[uint16(id1)][b.ID])
  1468  	}
  1469  	require.Equal(t, len(backends1), m.lbmap.DummyMaglevTable[uint16(id1)])
  1470  }
  1471  
  1472  // l7 load balancer service should be able to override any service type
  1473  // (Cluster IP, NodePort, etc.) with same frontend.
  1474  func TestL7LoadBalancerServiceOverride(t *testing.T) {
  1475  	m := setupManagerTestSuite(t)
  1476  
  1477  	// Create a node-local backend.
  1478  	localBackend := backends1[0]
  1479  	localBackend.NodeName = nodeTypes.GetName()
  1480  	// Create two remote backends.
  1481  	remoteBackends := make([]*lb.Backend, 0, len(backends2))
  1482  	for _, backend := range backends2 {
  1483  		backend.NodeName = "not-" + nodeTypes.GetName()
  1484  		remoteBackends = append(remoteBackends, backend)
  1485  	}
  1486  	allBackends := make([]*lb.Backend, 0, 1+len(remoteBackends))
  1487  	allBackends = append(allBackends, localBackend)
  1488  	allBackends = append(allBackends, remoteBackends...)
  1489  
  1490  	p1 := &lb.SVC{
  1491  		Frontend:         frontend1,
  1492  		Backends:         allBackends,
  1493  		Type:             lb.SVCTypeClusterIP,
  1494  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1495  		IntTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1496  		Name:             lb.ServiceName{Name: "echo-other-node", Namespace: "cilium-test"},
  1497  	}
  1498  
  1499  	// Insert the service entry of type ClusterIP.
  1500  	created, id, err := m.svc.UpsertService(p1)
  1501  	require.Nil(t, err)
  1502  	require.Equal(t, true, created)
  1503  	require.NotEqual(t, lb.ID(0), id)
  1504  
  1505  	svc, ok := m.svc.svcByID[id]
  1506  	require.Equal(t, len(allBackends), len(svc.backends))
  1507  	require.Equal(t, true, ok)
  1508  	require.Equal(t, uint16(0), svc.l7LBProxyPort)
  1509  
  1510  	// registering redirection with proxy port 0 should result in an error
  1511  	echoOtherNode := lb.ServiceName{Name: "echo-other-node", Namespace: "cilium-test"}
  1512  	resource1 := L7LBResourceName{Name: "testOwner1", Namespace: "cilium-test"}
  1513  	err = m.svc.RegisterL7LBServiceRedirect(echoOtherNode, resource1, 0, nil)
  1514  	require.Error(t, err)
  1515  
  1516  	svc, ok = m.svc.svcByID[id]
  1517  	require.Equal(t, len(allBackends), len(svc.backends))
  1518  	require.Equal(t, true, ok)
  1519  	require.Equal(t, uint16(0), svc.l7LBProxyPort)
  1520  
  1521  	// Registering with redirection stores the proxy port.
  1522  	resource2 := L7LBResourceName{Name: "testOwner2", Namespace: "cilium-test"}
  1523  	err = m.svc.RegisterL7LBServiceRedirect(echoOtherNode, resource2, 9090, nil)
  1524  	require.Nil(t, err)
  1525  
  1526  	svc, ok = m.svc.svcByID[id]
  1527  	require.Equal(t, len(allBackends), len(svc.backends))
  1528  	require.Equal(t, true, ok)
  1529  	require.Equal(t, uint16(9090), svc.l7LBProxyPort)
  1530  
  1531  	// registering redirection for a Service that already has a redirect registration
  1532  	// should result in an error.
  1533  	resource3 := L7LBResourceName{Name: "testOwner3", Namespace: "cilium-test"}
  1534  	err = m.svc.RegisterL7LBServiceRedirect(echoOtherNode, resource3, 10000, nil)
  1535  	require.Error(t, err)
  1536  
  1537  	// Remove with an unregistered owner name does not remove
  1538  	resource4 := L7LBResourceName{Name: "testOwner4", Namespace: "cilium-test"}
  1539  	err = m.svc.DeregisterL7LBServiceRedirect(echoOtherNode, resource4)
  1540  	require.Nil(t, err)
  1541  
  1542  	svc, ok = m.svc.svcByID[id]
  1543  	require.Equal(t, len(allBackends), len(svc.backends))
  1544  	require.Equal(t, true, ok)
  1545  	require.Equal(t, uint16(9090), svc.l7LBProxyPort)
  1546  
  1547  	// Removing registration without redirection does not remove the proxy port
  1548  	err = m.svc.DeregisterL7LBServiceRedirect(echoOtherNode, resource1)
  1549  	require.Nil(t, err)
  1550  
  1551  	svc, ok = m.svc.svcByID[id]
  1552  	require.Equal(t, len(allBackends), len(svc.backends))
  1553  	require.Equal(t, true, ok)
  1554  	require.Equal(t, uint16(9090), svc.l7LBProxyPort)
  1555  
  1556  	// removing the registration with redirection removes the proxy port
  1557  	err = m.svc.DeregisterL7LBServiceRedirect(echoOtherNode, resource2)
  1558  	require.Nil(t, err)
  1559  
  1560  	svc, ok = m.svc.svcByID[id]
  1561  	require.Equal(t, len(allBackends), len(svc.backends))
  1562  	require.Equal(t, true, ok)
  1563  	require.Equal(t, uint16(0), svc.l7LBProxyPort)
  1564  }
  1565  
  1566  // l7 load balancer service with ports should only override the given frontend ports.
  1567  func TestL7LoadBalancerServiceOverrideWithPorts(t *testing.T) {
  1568  	m := setupManagerTestSuite(t)
  1569  
  1570  	// Create a node-local backend.
  1571  	localBackend := backends1[0]
  1572  	localBackend.NodeName = nodeTypes.GetName()
  1573  	// Create two remote backends.
  1574  	remoteBackends := make([]*lb.Backend, 0, len(backends2))
  1575  	for _, backend := range backends2 {
  1576  		backend.NodeName = "not-" + nodeTypes.GetName()
  1577  		remoteBackends = append(remoteBackends, backend)
  1578  	}
  1579  	allBackends := make([]*lb.Backend, 0, 1+len(remoteBackends))
  1580  	allBackends = append(allBackends, localBackend)
  1581  	allBackends = append(allBackends, remoteBackends...)
  1582  
  1583  	p1 := &lb.SVC{
  1584  		Frontend:         frontend1,
  1585  		Backends:         allBackends,
  1586  		Type:             lb.SVCTypeClusterIP,
  1587  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1588  		IntTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1589  		Name:             lb.ServiceName{Name: "echo-other-node", Namespace: "cilium-test"},
  1590  	}
  1591  
  1592  	// Insert the service entry of type ClusterIP.
  1593  	created, id, err := m.svc.UpsertService(p1)
  1594  	require.Nil(t, err)
  1595  	require.Equal(t, true, created)
  1596  	require.NotEqual(t, lb.ID(0), id)
  1597  
  1598  	svc, ok := m.svc.svcByID[id]
  1599  	require.Equal(t, len(allBackends), len(svc.backends))
  1600  	require.Equal(t, true, ok)
  1601  	require.Equal(t, uint16(0), svc.l7LBProxyPort)
  1602  
  1603  	echoOtherNode := lb.ServiceName{Name: "echo-other-node", Namespace: "cilium-test"}
  1604  	resource1 := L7LBResourceName{Name: "testOwner1", Namespace: "cilium-test"}
  1605  
  1606  	// Registering with redirection stores the proxy port.
  1607  	resource2 := L7LBResourceName{Name: "testOwner2", Namespace: "cilium-test"}
  1608  	err = m.svc.RegisterL7LBServiceRedirect(echoOtherNode, resource2, 9090, []uint16{80})
  1609  	require.Nil(t, err)
  1610  
  1611  	svc, ok = m.svc.svcByID[id]
  1612  	require.Equal(t, len(allBackends), len(svc.backends))
  1613  	require.Equal(t, true, ok)
  1614  	require.Equal(t, uint16(9090), svc.l7LBProxyPort)
  1615  
  1616  	// removing the registration with redirection removes the proxy port
  1617  	err = m.svc.DeregisterL7LBServiceRedirect(echoOtherNode, resource2)
  1618  	require.Nil(t, err)
  1619  
  1620  	svc, ok = m.svc.svcByID[id]
  1621  	require.Equal(t, len(allBackends), len(svc.backends))
  1622  	require.Equal(t, true, ok)
  1623  	require.Equal(t, uint16(0), svc.l7LBProxyPort)
  1624  
  1625  	// Registering with non-matching port does not store the proxy port.
  1626  	err = m.svc.RegisterL7LBServiceRedirect(echoOtherNode, resource2, 9090, []uint16{8080})
  1627  	require.Nil(t, err)
  1628  
  1629  	svc, ok = m.svc.svcByID[id]
  1630  	require.Equal(t, len(allBackends), len(svc.backends))
  1631  	require.Equal(t, true, ok)
  1632  	require.Equal(t, uint16(0), svc.l7LBProxyPort)
  1633  
  1634  	// registering redirection for a Service that already has a redirect registration
  1635  	// should result in an error.
  1636  	resource3 := L7LBResourceName{Name: "testOwner3", Namespace: "cilium-test"}
  1637  	err = m.svc.RegisterL7LBServiceRedirect(echoOtherNode, resource3, 10000, nil)
  1638  	require.Error(t, err)
  1639  
  1640  	// Adding a matching frontend gets proxy port
  1641  
  1642  	p2 := &lb.SVC{
  1643  		Frontend:         frontend1_8080,
  1644  		Backends:         allBackends,
  1645  		Type:             lb.SVCTypeClusterIP,
  1646  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1647  		IntTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1648  		Name:             lb.ServiceName{Name: "echo-other-node", Namespace: "cilium-test"},
  1649  	}
  1650  
  1651  	// Insert the service entry of type ClusterIP.
  1652  	created, id2, err := m.svc.UpsertService(p2)
  1653  	require.Nil(t, err)
  1654  	require.Equal(t, true, created)
  1655  	require.NotEqual(t, lb.ID(0), id2)
  1656  
  1657  	svc, ok = m.svc.svcByID[id2]
  1658  	require.Equal(t, len(allBackends), len(svc.backends))
  1659  	require.Equal(t, true, ok)
  1660  	require.Equal(t, uint16(9090), svc.l7LBProxyPort)
  1661  
  1662  	// Remove with an unregistered owner name does not remove
  1663  	resource4 := L7LBResourceName{Name: "testOwner4", Namespace: "cilium-test"}
  1664  	err = m.svc.DeregisterL7LBServiceRedirect(echoOtherNode, resource4)
  1665  	require.Nil(t, err)
  1666  
  1667  	svc, ok = m.svc.svcByID[id2]
  1668  	require.Equal(t, len(allBackends), len(svc.backends))
  1669  	require.Equal(t, true, ok)
  1670  	require.Equal(t, uint16(9090), svc.l7LBProxyPort)
  1671  
  1672  	// Removing registration without redirection does not remove the proxy port
  1673  	err = m.svc.DeregisterL7LBServiceRedirect(echoOtherNode, resource1)
  1674  	require.Nil(t, err)
  1675  
  1676  	svc, ok = m.svc.svcByID[id2]
  1677  	require.Equal(t, len(allBackends), len(svc.backends))
  1678  	require.Equal(t, true, ok)
  1679  	require.Equal(t, uint16(9090), svc.l7LBProxyPort)
  1680  
  1681  	// removing the registration with redirection removes the proxy port
  1682  	err = m.svc.DeregisterL7LBServiceRedirect(echoOtherNode, resource2)
  1683  	require.Nil(t, err)
  1684  
  1685  	svc, ok = m.svc.svcByID[id]
  1686  	require.Equal(t, len(allBackends), len(svc.backends))
  1687  	require.Equal(t, true, ok)
  1688  	require.Equal(t, uint16(0), svc.l7LBProxyPort)
  1689  
  1690  	svc, ok = m.svc.svcByID[id2]
  1691  	require.Equal(t, len(allBackends), len(svc.backends))
  1692  	require.Equal(t, true, ok)
  1693  	require.Equal(t, uint16(0), svc.l7LBProxyPort)
  1694  }
  1695  
  1696  // L7 LB proxies should be able to register callback based backend sync registration
  1697  func TestL7LoadBalancerServiceBackendSyncRegistration(t *testing.T) {
  1698  	m := setupManagerTestSuite(t)
  1699  
  1700  	// Create a node-local backend.
  1701  	localBackend := backends1[0]
  1702  	localBackend.NodeName = nodeTypes.GetName()
  1703  	// Create two remote backends.
  1704  	remoteBackends := make([]*lb.Backend, 0, len(backends2))
  1705  	for _, backend := range backends2 {
  1706  		backend.NodeName = "not-" + nodeTypes.GetName()
  1707  		remoteBackends = append(remoteBackends, backend)
  1708  	}
  1709  	allBackends := make([]*lb.Backend, 0, 1+len(remoteBackends))
  1710  	allBackends = append(allBackends, localBackend)
  1711  	allBackends = append(allBackends, remoteBackends...)
  1712  
  1713  	p1 := &lb.SVC{
  1714  		Frontend:         frontend1,
  1715  		Backends:         allBackends,
  1716  		Type:             lb.SVCTypeClusterIP,
  1717  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1718  		IntTrafficPolicy: lb.SVCTrafficPolicyCluster,
  1719  		Name:             lb.ServiceName{Name: "echo-other-node", Namespace: "cilium-test"},
  1720  	}
  1721  
  1722  	// Insert the service entry of type ClusterIP.
  1723  	created, id, err := m.svc.UpsertService(p1)
  1724  	require.Nil(t, err)
  1725  	require.Equal(t, true, created)
  1726  	require.NotEqual(t, lb.ID(0), id)
  1727  
  1728  	// Registering L7LB backend sync should register backend sync and trigger an initial synchronization
  1729  	service := lb.ServiceName{Name: "echo-other-node", Namespace: "cilium-test"}
  1730  	backendSyncer := &FakeBackendSyncer{}
  1731  	err = m.svc.RegisterL7LBServiceBackendSync(service, backendSyncer)
  1732  	require.Nil(t, err)
  1733  
  1734  	require.Equal(t, 1, len(m.svc.l7lbSvcs))
  1735  	require.Equal(t, 1, len(m.svc.l7lbSvcs[service].backendSyncRegistrations))
  1736  	require.Equal(t, len(allBackends), backendSyncer.nrOfBackends)
  1737  	require.Equal(t, 1, backendSyncer.nrOfSyncs)
  1738  
  1739  	// Re-Registering L7LB backend sync should keep the existing registration and trigger an implicit re-synchronization
  1740  	err = m.svc.RegisterL7LBServiceBackendSync(service, backendSyncer)
  1741  	require.Nil(t, err)
  1742  
  1743  	require.Equal(t, 1, len(m.svc.l7lbSvcs))
  1744  	require.Equal(t, 1, len(m.svc.l7lbSvcs[service].backendSyncRegistrations))
  1745  	require.Equal(t, len(allBackends), backendSyncer.nrOfBackends)
  1746  	require.Equal(t, 2, backendSyncer.nrOfSyncs)
  1747  
  1748  	// Upserting a service should trigger a sync for the registered backend sync registrations
  1749  	allBackends = append(allBackends, backends4...)
  1750  	p1.Backends = allBackends
  1751  	created, id, err = m.svc.UpsertService(p1)
  1752  	require.Nil(t, err)
  1753  	require.Equal(t, false, created)
  1754  	require.NotEqual(t, lb.ID(0), id)
  1755  
  1756  	require.Equal(t, 1, len(m.svc.l7lbSvcs))
  1757  	require.Equal(t, 1, len(m.svc.l7lbSvcs[service].backendSyncRegistrations))
  1758  	require.Equal(t, len(allBackends), backendSyncer.nrOfBackends)
  1759  	require.Equal(t, 3, backendSyncer.nrOfSyncs)
  1760  
  1761  	// De-registering a backend sync should delete the backend sync registration
  1762  	err = m.svc.DeregisterL7LBServiceBackendSync(service, backendSyncer)
  1763  	require.Nil(t, err)
  1764  
  1765  	require.Equal(t, 0, len(m.svc.l7lbSvcs))
  1766  	require.Equal(t, len(allBackends), backendSyncer.nrOfBackends)
  1767  	require.Equal(t, 3, backendSyncer.nrOfSyncs)
  1768  }
  1769  
  1770  // Tests that services with the given backends are updated with the new backend
  1771  // state.
  1772  func TestUpdateBackendsState(t *testing.T) {
  1773  	m := setupManagerTestSuite(t)
  1774  
  1775  	backends := make([]*lb.Backend, 0, len(backends1))
  1776  	for _, b := range backends1 {
  1777  		backends = append(backends, b.DeepCopy())
  1778  	}
  1779  	backends[0].State = lb.BackendStateActive
  1780  	backends[1].State = lb.BackendStateActive
  1781  	p1 := &lb.SVC{
  1782  		Frontend: frontend1,
  1783  		Backends: backends,
  1784  		Type:     lb.SVCTypeClusterIP,
  1785  		Name:     lb.ServiceName{Name: "svc1", Namespace: "ns1"},
  1786  	}
  1787  	p2 := &lb.SVC{
  1788  		Frontend: frontend2,
  1789  		Backends: backends,
  1790  		Type:     lb.SVCTypeClusterIP,
  1791  		Name:     lb.ServiceName{Name: "svc2", Namespace: "ns1"},
  1792  	}
  1793  
  1794  	_, id1, err1 := m.svc.UpsertService(p1)
  1795  	_, id2, err2 := m.svc.UpsertService(p2)
  1796  
  1797  	require.Nil(t, err1)
  1798  	require.Nil(t, err2)
  1799  	require.Equal(t, lb.ID(1), id1)
  1800  	require.Equal(t, lb.ID(2), id2)
  1801  	require.Equal(t, lb.BackendStateActive, m.svc.svcByID[id1].backends[0].State)
  1802  	require.Equal(t, lb.BackendStateActive, m.svc.svcByID[id1].backends[1].State)
  1803  	require.Equal(t, lb.BackendStateActive, m.svc.svcByID[id2].backends[0].State)
  1804  	require.Equal(t, lb.BackendStateActive, m.svc.svcByID[id2].backends[1].State)
  1805  	require.Equal(t, len(backends), len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1806  	require.Equal(t, len(backends), len(m.lbmap.ServiceByID[uint16(id2)].Backends))
  1807  	require.Equal(t, len(backends), m.lbmap.SvcActiveBackendsCount[uint16(id1)])
  1808  	require.Equal(t, len(backends), m.lbmap.SvcActiveBackendsCount[uint16(id2)])
  1809  	require.Equal(t, len(backends), len(m.lbmap.BackendByID))
  1810  	// Backend states are persisted in the map.
  1811  	require.Equal(t, lb.BackendStateActive, m.lbmap.BackendByID[1].State)
  1812  	require.Equal(t, lb.BackendStateActive, m.lbmap.BackendByID[2].State)
  1813  
  1814  	// Update the state for one of the backends.
  1815  	updated := []*lb.Backend{backends[0]}
  1816  	updated[0].State = lb.BackendStateQuarantined
  1817  
  1818  	err := m.svc.UpdateBackendsState(updated)
  1819  
  1820  	require.Nil(t, err)
  1821  	// Both the services are updated with the update backend state.
  1822  	require.Equal(t, lb.BackendStateQuarantined, m.svc.svcByID[id1].backends[0].State)
  1823  	require.Equal(t, lb.BackendStateActive, m.svc.svcByID[id1].backends[1].State)
  1824  	require.Equal(t, lb.BackendStateQuarantined, m.svc.svcByID[id2].backends[0].State)
  1825  	require.Equal(t, lb.BackendStateActive, m.svc.svcByID[id2].backends[1].State)
  1826  	require.Equal(t, len(backends), len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1827  	require.Equal(t, len(backends), len(m.lbmap.ServiceByID[uint16(id2)].Backends))
  1828  	require.Equal(t, 1, m.lbmap.SvcActiveBackendsCount[uint16(id1)])
  1829  	require.Equal(t, 1, m.lbmap.SvcActiveBackendsCount[uint16(id2)])
  1830  	require.Equal(t, len(backends), len(m.lbmap.BackendByID))
  1831  	// Updated backend states are persisted in the map.
  1832  	require.Equal(t, lb.BackendStateQuarantined, m.lbmap.BackendByID[1].State)
  1833  	require.Equal(t, lb.BackendStateActive, m.lbmap.BackendByID[2].State)
  1834  
  1835  	// Update the state again.
  1836  	updated = []*lb.Backend{backends[0]}
  1837  	updated[0].State = lb.BackendStateActive
  1838  
  1839  	err = m.svc.UpdateBackendsState(updated)
  1840  
  1841  	require.Nil(t, err)
  1842  	// Both the services are updated with the update backend state.
  1843  	require.Equal(t, lb.BackendStateActive, m.svc.svcByID[id1].backends[0].State)
  1844  	require.Equal(t, lb.BackendStateActive, m.svc.svcByID[id1].backends[1].State)
  1845  	require.Equal(t, lb.BackendStateActive, m.svc.svcByID[id2].backends[0].State)
  1846  	require.Equal(t, lb.BackendStateActive, m.svc.svcByID[id2].backends[1].State)
  1847  	require.Equal(t, len(backends), len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1848  	require.Equal(t, len(backends), len(m.lbmap.ServiceByID[uint16(id2)].Backends))
  1849  	require.Equal(t, len(backends), m.lbmap.SvcActiveBackendsCount[uint16(id1)])
  1850  	require.Equal(t, len(backends), m.lbmap.SvcActiveBackendsCount[uint16(id2)])
  1851  	require.Equal(t, len(backends), len(m.lbmap.BackendByID))
  1852  	// Updated backend states are persisted in the map.
  1853  	require.Equal(t, lb.BackendStateActive, m.lbmap.BackendByID[1].State)
  1854  	require.Equal(t, lb.BackendStateActive, m.lbmap.BackendByID[2].State)
  1855  }
  1856  
  1857  // Tests that backend states are restored.
  1858  func TestRestoreServiceWithBackendStates(t *testing.T) {
  1859  	m := setupManagerTestSuite(t)
  1860  
  1861  	option.Config.NodePortAlg = option.NodePortAlgMaglev
  1862  	bs := append(backends1, backends4...)
  1863  	backends := make([]*lb.Backend, 0, len(bs))
  1864  	for _, b := range bs {
  1865  		backends = append(backends, b.DeepCopy())
  1866  	}
  1867  	backends[0].State = lb.BackendStateActive
  1868  	backends[1].State = lb.BackendStateActive
  1869  	backends[2].State = lb.BackendStateActive
  1870  
  1871  	p1 := &lb.SVC{
  1872  		Frontend:                  frontend1,
  1873  		Backends:                  backends,
  1874  		SessionAffinity:           true,
  1875  		SessionAffinityTimeoutSec: 100,
  1876  		Type:                      lb.SVCTypeNodePort,
  1877  		ExtTrafficPolicy:          lb.SVCTrafficPolicyCluster,
  1878  		IntTrafficPolicy:          lb.SVCTrafficPolicyCluster,
  1879  	}
  1880  	created, id1, err := m.svc.UpsertService(p1)
  1881  
  1882  	require.Nil(t, err)
  1883  	require.Equal(t, true, created)
  1884  	require.Equal(t, lb.ID(1), id1)
  1885  	require.Equal(t, len(backends), len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1886  	require.Equal(t, len(backends), len(m.svc.backendByHash))
  1887  
  1888  	// Update backend states.
  1889  	var updates []*lb.Backend
  1890  	backends[0].State = lb.BackendStateQuarantined
  1891  	backends[1].State = lb.BackendStateMaintenance
  1892  	updates = append(updates, backends[0], backends[1])
  1893  	err = m.svc.UpdateBackendsState(updates)
  1894  
  1895  	require.Nil(t, err)
  1896  
  1897  	// Simulate agent restart.
  1898  	lbmap := m.svc.lbmap.(*mockmaps.LBMockMap)
  1899  	m.newServiceMock(lbmap)
  1900  
  1901  	// Restore services from lbmap
  1902  	err = m.svc.RestoreServices()
  1903  	require.Nil(t, err)
  1904  
  1905  	// Check that backends along with their states have been restored
  1906  	require.Equal(t, len(backends), len(m.svc.backendByHash))
  1907  	statesMatched := 0
  1908  	for _, b := range backends {
  1909  		be, found := m.svc.backendByHash[b.Hash()]
  1910  		require.Equal(t, true, found)
  1911  		if be.String() == b.String() {
  1912  			require.Equal(t, b.State, be.State, "before %+v restored %+v", b, be)
  1913  			statesMatched++
  1914  		}
  1915  	}
  1916  	require.Equal(t, len(backends), statesMatched)
  1917  	require.Equal(t, 1, m.lbmap.DummyMaglevTable[uint16(id1)])
  1918  }
  1919  
  1920  func TestUpsertServiceWithZeroWeightBackends(t *testing.T) {
  1921  	m := setupManagerTestSuite(t)
  1922  
  1923  	option.Config.NodePortAlg = option.NodePortAlgMaglev
  1924  	backends := append(backends1, backends4...)
  1925  	backends[1].Weight = 0
  1926  	backends[1].State = lb.BackendStateMaintenance
  1927  	backends[2].Weight = 1
  1928  
  1929  	p := &lb.SVC{
  1930  		Frontend:                  frontend1,
  1931  		Backends:                  backends,
  1932  		Type:                      lb.SVCTypeNodePort,
  1933  		ExtTrafficPolicy:          lb.SVCTrafficPolicyCluster,
  1934  		IntTrafficPolicy:          lb.SVCTrafficPolicyCluster,
  1935  		SessionAffinity:           true,
  1936  		SessionAffinityTimeoutSec: 100,
  1937  		Name: lb.ServiceName{
  1938  			Name:      "svc1",
  1939  			Namespace: "ns1",
  1940  		},
  1941  	}
  1942  
  1943  	created, id1, err := m.svc.UpsertService(p)
  1944  
  1945  	require.Nil(t, err)
  1946  	require.Equal(t, true, created)
  1947  	require.Equal(t, 3, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1948  	require.Equal(t, 3, len(m.lbmap.BackendByID))
  1949  	hash := backends[1].L3n4Addr.Hash()
  1950  	require.Equal(t, lb.BackendStateMaintenance, m.svc.backendByHash[hash].State)
  1951  	require.Equal(t, lb.BackendStateMaintenance, m.svc.svcByID[id1].backendByHash[hash].State)
  1952  	hash2 := backends[2].L3n4Addr.Hash()
  1953  	require.Equal(t, lb.BackendStateActive, m.svc.backendByHash[hash2].State)
  1954  	require.Equal(t, lb.BackendStateActive, m.svc.svcByID[id1].backendByHash[hash2].State)
  1955  	require.Equal(t, 2, m.lbmap.DummyMaglevTable[uint16(id1)])
  1956  
  1957  	// Update existing backend weight
  1958  	p.Backends[2].Weight = 0
  1959  	p.Backends[2].State = lb.BackendStateMaintenance
  1960  
  1961  	created, id1, err = m.svc.UpsertService(p)
  1962  
  1963  	require.Nil(t, err)
  1964  	require.Equal(t, false, created)
  1965  	require.Equal(t, 3, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1966  	require.Equal(t, 3, len(m.lbmap.BackendByID))
  1967  	require.Equal(t, lb.BackendStateMaintenance, m.svc.svcByID[id1].backendByHash[hash2].State)
  1968  	require.Equal(t, 1, m.lbmap.DummyMaglevTable[uint16(id1)])
  1969  
  1970  	// Delete backends with weight 0
  1971  	p.Backends = backends[:1]
  1972  
  1973  	created, id1, err = m.svc.UpsertService(p)
  1974  
  1975  	require.Nil(t, err)
  1976  	require.Equal(t, false, created)
  1977  	require.Equal(t, 1, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  1978  	require.Equal(t, 1, len(m.lbmap.BackendByID))
  1979  	require.Equal(t, 1, m.lbmap.DummyMaglevTable[uint16(id1)])
  1980  }
  1981  
  1982  func TestUpdateBackendsStateWithBackendSharedAcrossServices(t *testing.T) {
  1983  	m := setupManagerTestSuite(t)
  1984  
  1985  	option.Config.NodePortAlg = option.NodePortAlgMaglev
  1986  	be := append(backends1, backends4...)
  1987  	backends := make([]*lb.Backend, 0, len(be))
  1988  	for _, b := range be {
  1989  		backends = append(backends, b.DeepCopy())
  1990  	}
  1991  	backends[0].State = lb.BackendStateActive
  1992  	backends[1].State = lb.BackendStateActive
  1993  	backends[2].State = lb.BackendStateMaintenance
  1994  	hash0 := backends[0].L3n4Addr.Hash()
  1995  	hash1 := backends[1].L3n4Addr.Hash()
  1996  	hash2 := backends[2].L3n4Addr.Hash()
  1997  
  1998  	p := &lb.SVC{
  1999  		Frontend:                  frontend1,
  2000  		Backends:                  backends,
  2001  		Type:                      lb.SVCTypeNodePort,
  2002  		ExtTrafficPolicy:          lb.SVCTrafficPolicyCluster,
  2003  		IntTrafficPolicy:          lb.SVCTrafficPolicyCluster,
  2004  		SessionAffinity:           true,
  2005  		SessionAffinityTimeoutSec: 100,
  2006  		Name: lb.ServiceName{
  2007  			Name:      "svc1",
  2008  			Namespace: "ns1",
  2009  		},
  2010  	}
  2011  	r := &lb.SVC{
  2012  		Frontend:                  frontend2,
  2013  		Backends:                  backends,
  2014  		Type:                      lb.SVCTypeNodePort,
  2015  		ExtTrafficPolicy:          lb.SVCTrafficPolicyCluster,
  2016  		IntTrafficPolicy:          lb.SVCTrafficPolicyCluster,
  2017  		SessionAffinity:           true,
  2018  		SessionAffinityTimeoutSec: 100,
  2019  		Name: lb.ServiceName{
  2020  			Name:      "svc2",
  2021  			Namespace: "ns1",
  2022  		},
  2023  	}
  2024  	svcHash2 := r.Frontend.Hash()
  2025  
  2026  	_, _, err := m.svc.UpsertService(p)
  2027  	require.Nil(t, err)
  2028  	_, _, err = m.svc.UpsertService(r)
  2029  	require.Nil(t, err)
  2030  	_, id1, err := m.svc.UpsertService(r)
  2031  
  2032  	// Assert expected backend states after consecutive upsert service calls that share the backends.
  2033  	require.Nil(t, err)
  2034  	require.Equal(t, 3, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  2035  	require.Equal(t, 3, len(m.lbmap.BackendByID))
  2036  	require.Equal(t, lb.BackendStateActive, m.svc.backendByHash[hash0].State)
  2037  	require.Equal(t, lb.BackendStateActive, m.svc.backendByHash[hash1].State)
  2038  	require.Equal(t, lb.BackendStateMaintenance, m.svc.backendByHash[hash2].State)
  2039  
  2040  	backends[1].State = lb.BackendStateMaintenance
  2041  	err = m.svc.UpdateBackendsState(backends)
  2042  
  2043  	require.Nil(t, err)
  2044  	require.Equal(t, lb.BackendStateMaintenance, m.svc.backendByHash[hash1].State)
  2045  	require.Equal(t, lb.BackendStateMaintenance, m.svc.svcByHash[svcHash2].backends[1].State)
  2046  	require.Equal(t, lb.BackendStateMaintenance, m.svc.svcByHash[svcHash2].backendByHash[hash1].State)
  2047  }
  2048  
  2049  func TestSyncNodePortFrontends(t *testing.T) {
  2050  	m := setupManagerTestSuite(t)
  2051  
  2052  	// Add a IPv4 surrogate frontend
  2053  	surrogate := &lb.SVC{
  2054  		Frontend: surrogateFE,
  2055  		Backends: backends1,
  2056  		Type:     lb.SVCTypeNodePort,
  2057  	}
  2058  	_, surrID, err := m.svc.UpsertService(surrogate)
  2059  	require.Nil(t, err)
  2060  	p1 := &lb.SVC{
  2061  		Frontend: frontend1,
  2062  		Backends: backends1,
  2063  		Type:     lb.SVCTypeNodePort,
  2064  	}
  2065  	_, _, err = m.svc.UpsertService(p1)
  2066  	require.Nil(t, err)
  2067  	require.Equal(t, 2, len(m.svc.svcByID))
  2068  
  2069  	// With no addresses all frontends (except surrogates) should be removed.
  2070  	err = m.svc.SyncNodePortFrontends(sets.New[netip.Addr]())
  2071  	require.Nil(t, err)
  2072  
  2073  	require.Equal(t, 1, len(m.svc.svcByID))
  2074  	_, ok := m.svc.svcByID[surrID]
  2075  	require.Equal(t, true, ok)
  2076  
  2077  	// With a new frontend addresses services should be re-created.
  2078  	nodeAddrs := sets.New[netip.Addr](
  2079  		frontend1.AddrCluster.Addr(),
  2080  		frontend2.AddrCluster.Addr(),
  2081  		// IPv6 address should be ignored initially without IPv6 surrogate
  2082  		frontend3.AddrCluster.Addr(),
  2083  	)
  2084  	m.svc.SyncNodePortFrontends(nodeAddrs)
  2085  	require.Equal(t, 2+1 /* surrogate */, len(m.svc.svcByID))
  2086  
  2087  	_, _, found := m.svc.GetServiceNameByAddr(frontend1.L3n4Addr)
  2088  	require.Equal(t, true, found)
  2089  	_, _, found = m.svc.GetServiceNameByAddr(frontend2.L3n4Addr)
  2090  	require.Equal(t, true, found)
  2091  
  2092  	// Add an IPv6 surrogate
  2093  	surrogate = &lb.SVC{
  2094  		Frontend: surrogateFEv6,
  2095  		Backends: backends3,
  2096  		Type:     lb.SVCTypeNodePort,
  2097  	}
  2098  	_, _, err = m.svc.UpsertService(surrogate)
  2099  	require.Nil(t, err)
  2100  
  2101  	err = m.svc.SyncNodePortFrontends(nodeAddrs)
  2102  	require.Nil(t, err)
  2103  	require.Equal(t, 3+2 /* surrogates */, len(m.svc.svcByID))
  2104  }
  2105  
  2106  func TestTrafficPolicy(t *testing.T) {
  2107  	m := setupManagerTestSuite(t)
  2108  
  2109  	internalIP := *lb.NewL3n4AddrID(lb.TCP, cmtypes.MustParseAddrCluster("1.1.1.1"), 80, lb.ScopeInternal, 0)
  2110  	externalIP := *lb.NewL3n4AddrID(lb.TCP, cmtypes.MustParseAddrCluster("1.1.1.1"), 80, lb.ScopeExternal, 0)
  2111  
  2112  	localBackend1 := lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.1"), 8080)
  2113  	localBackend2 := lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.2"), 8080)
  2114  	localBackend1.NodeName = nodeTypes.GetName()
  2115  	localBackend2.NodeName = nodeTypes.GetName()
  2116  	localBackends := []*lb.Backend{localBackend1, localBackend2}
  2117  
  2118  	remoteBackend1 := lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.3"), 8080)
  2119  	remoteBackend2 := lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.4"), 8080)
  2120  	remoteBackend3 := lb.NewBackend(0, lb.TCP, cmtypes.MustParseAddrCluster("10.0.0.5"), 8080)
  2121  	remoteBackend1.NodeName = "not-" + nodeTypes.GetName()
  2122  	remoteBackend2.NodeName = "not-" + nodeTypes.GetName()
  2123  	remoteBackend3.NodeName = "not-" + nodeTypes.GetName()
  2124  	remoteBackends := []*lb.Backend{remoteBackend1, remoteBackend2, remoteBackend3}
  2125  
  2126  	allBackends := make([]*lb.Backend, 0, len(remoteBackends)+len(remoteBackends))
  2127  	allBackends = append(allBackends, localBackends...)
  2128  	allBackends = append(allBackends, remoteBackends...)
  2129  
  2130  	p1 := &lb.SVC{
  2131  		Frontend:         internalIP,
  2132  		Backends:         allBackends,
  2133  		Type:             lb.SVCTypeLoadBalancer,
  2134  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
  2135  		IntTrafficPolicy: lb.SVCTrafficPolicyLocal,
  2136  		Name:             lb.ServiceName{Name: "svc1", Namespace: "ns1"},
  2137  	}
  2138  	created, id1, err := m.svc.UpsertService(p1)
  2139  	require.Equal(t, true, created)
  2140  	require.Nil(t, err)
  2141  
  2142  	p2 := &lb.SVC{
  2143  		Frontend:         externalIP,
  2144  		Backends:         allBackends,
  2145  		Type:             lb.SVCTypeLoadBalancer,
  2146  		ExtTrafficPolicy: lb.SVCTrafficPolicyCluster,
  2147  		IntTrafficPolicy: lb.SVCTrafficPolicyLocal,
  2148  		Name:             lb.ServiceName{Name: "svc1", Namespace: "ns1"},
  2149  	}
  2150  	created, id2, err := m.svc.UpsertService(p2)
  2151  	require.Equal(t, true, created)
  2152  	require.Nil(t, err)
  2153  
  2154  	svcFromLbMap1, ok := m.lbmap.ServiceByID[uint16(id1)]
  2155  	require.Equal(t, true, ok)
  2156  	require.Equal(t, len(localBackends), len(svcFromLbMap1.Backends))
  2157  
  2158  	svcFromLbMap2, ok := m.lbmap.ServiceByID[uint16(id2)]
  2159  	require.Equal(t, true, ok)
  2160  	require.Equal(t, len(allBackends), len(svcFromLbMap2.Backends))
  2161  
  2162  	p1.ExtTrafficPolicy = lb.SVCTrafficPolicyLocal
  2163  	p1.IntTrafficPolicy = lb.SVCTrafficPolicyCluster
  2164  	created, id3, err := m.svc.UpsertService(p1)
  2165  	require.Equal(t, false, created)
  2166  	require.Nil(t, err)
  2167  	require.Equal(t, id1, id3)
  2168  
  2169  	svcFromLbMap3, ok := m.lbmap.ServiceByID[uint16(id1)]
  2170  	require.Equal(t, true, ok)
  2171  	require.Equal(t, len(allBackends), len(svcFromLbMap3.Backends))
  2172  
  2173  	p2.ExtTrafficPolicy = lb.SVCTrafficPolicyLocal
  2174  	p2.IntTrafficPolicy = lb.SVCTrafficPolicyCluster
  2175  	created, id4, err := m.svc.UpsertService(p2)
  2176  	require.Equal(t, false, created)
  2177  	require.Nil(t, err)
  2178  	require.Equal(t, id2, id4)
  2179  
  2180  	svcFromLbMap4, ok := m.lbmap.ServiceByID[uint16(id2)]
  2181  	require.Equal(t, true, ok)
  2182  	require.Equal(t, len(localBackends), len(svcFromLbMap4.Backends))
  2183  
  2184  	found, err := m.svc.DeleteServiceByID(lb.ServiceID(id1))
  2185  	require.Nil(t, err)
  2186  	require.Equal(t, true, found)
  2187  	found, err = m.svc.DeleteServiceByID(lb.ServiceID(id2))
  2188  	require.Nil(t, err)
  2189  	require.Equal(t, true, found)
  2190  }
  2191  
  2192  // Tests whether delete service handles non-active backends.
  2193  func TestDeleteServiceWithTerminatingBackends(t *testing.T) {
  2194  	m := setupManagerTestSuite(t)
  2195  
  2196  	backends := backends5
  2197  	backends[0].State = lb.BackendStateTerminating
  2198  	p := &lb.SVC{
  2199  		Frontend: frontend1,
  2200  		Backends: backends,
  2201  		Name:     lb.ServiceName{Name: "svc1", Namespace: "ns1"},
  2202  	}
  2203  
  2204  	created, id1, err := m.svc.UpsertService(p)
  2205  
  2206  	require.Nil(t, err)
  2207  	require.Equal(t, true, created)
  2208  	require.Equal(t, lb.ID(1), id1)
  2209  	require.Equal(t, 2, len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  2210  	require.Equal(t, 2, len(m.lbmap.BackendByID))
  2211  	require.Equal(t, lb.ServiceName{Name: "svc1", Namespace: "ns1"}, m.svc.svcByID[id1].svcName)
  2212  
  2213  	// Delete service.
  2214  	found, err := m.svc.DeleteServiceByID(lb.ServiceID(id1))
  2215  
  2216  	require.Nil(t, err)
  2217  	require.Equal(t, true, found)
  2218  	require.Equal(t, 0, len(m.lbmap.ServiceByID))
  2219  	require.Equal(t, 0, len(m.lbmap.BackendByID))
  2220  }
  2221  
  2222  func TestRestoreServicesWithLeakedBackends(t *testing.T) {
  2223  	m := setupManagerTestSuite(t)
  2224  
  2225  	backends := make([]*lb.Backend, len(backends1))
  2226  	backends[0] = backends1[0].DeepCopy()
  2227  	backends[1] = backends1[1].DeepCopy()
  2228  	p1 := &lb.SVC{
  2229  		Frontend: frontend1,
  2230  		Backends: backends,
  2231  		Type:     lb.SVCTypeClusterIP,
  2232  		Name:     lb.ServiceName{Name: "svc1", Namespace: "ns1"},
  2233  	}
  2234  
  2235  	_, id1, err1 := m.svc.UpsertService(p1)
  2236  
  2237  	require.Nil(t, err1)
  2238  	require.Equal(t, lb.ID(1), id1)
  2239  	require.Equal(t, len(backends), len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  2240  	require.Equal(t, len(backends), len(m.lbmap.BackendByID))
  2241  
  2242  	// Simulate leaked backends with various leaked scenarios.
  2243  	// Backend2 is a duplicate leaked backend with the same L3nL4Addr as backends[0]
  2244  	// that's associated with the service.
  2245  	// Backend3 is a leaked backend with no associated service.
  2246  	// Backend4 and Backend5 are duplicate leaked backends with no associated service.
  2247  	backend2 := backends[0].DeepCopy()
  2248  	backend2.ID = lb.BackendID(10)
  2249  	backend3 := backends2[0].DeepCopy()
  2250  	backend4 := backends6[0].DeepCopy()
  2251  	backend4.ID = lb.BackendID(20)
  2252  	backend5 := backends6[0].DeepCopy()
  2253  	backend5.ID = lb.BackendID(30)
  2254  	m.svc.lbmap.AddBackend(backend2, backend2.L3n4Addr.IsIPv6())
  2255  	m.svc.lbmap.AddBackend(backend3, backend3.L3n4Addr.IsIPv6())
  2256  	m.svc.lbmap.AddBackend(backend4, backend4.L3n4Addr.IsIPv6())
  2257  	m.svc.lbmap.AddBackend(backend5, backend5.L3n4Addr.IsIPv6())
  2258  	require.Equal(t, len(backends)+4, len(m.lbmap.BackendByID))
  2259  	lbmap := m.svc.lbmap.(*mockmaps.LBMockMap)
  2260  	m.svc = newService(&FakeMonitorAgent{}, lbmap, nil)
  2261  
  2262  	// Restore services from lbmap
  2263  	err := m.svc.RestoreServices()
  2264  	require.Nil(t, err)
  2265  	require.Equal(t, len(backends), len(m.lbmap.ServiceByID[uint16(id1)].Backends))
  2266  	// Leaked backends should be deleted.
  2267  	require.Equal(t, len(backends), len(m.lbmap.BackendByID))
  2268  }
  2269  
  2270  // Tests backend connections getting destroyed.
  2271  func TestUpsertServiceWithDeletedBackends(t *testing.T) {
  2272  	m := setupManagerTestSuite(t)
  2273  
  2274  	option.Config.EnableSocketLB = true
  2275  	backends := []*lb.Backend{
  2276  		lb.NewBackend(0, lb.UDP, cmtypes.MustParseAddrCluster("10.0.0.1"), 8080),
  2277  		lb.NewBackend(0, lb.UDP, cmtypes.MustParseAddrCluster("10.0.0.2"), 8080),
  2278  	}
  2279  	cookie1 := [2]uint32{1234, 0}
  2280  	cookie2 := [2]uint32{1235, 0}
  2281  	id1 := netlink.SocketID{
  2282  		DestinationPort: 8080,
  2283  		Destination:     backends[0].L3n4Addr.AddrCluster.Addr().AsSlice(),
  2284  		Cookie:          cookie1,
  2285  	}
  2286  	id2 := netlink.SocketID{
  2287  		DestinationPort: 8080,
  2288  		Destination:     backends[1].L3n4Addr.AddrCluster.Addr().AsSlice(),
  2289  		Cookie:          cookie2,
  2290  	}
  2291  	// Socket connected to backend1
  2292  	s1 := testsockets.MockSocket{
  2293  		SockID: id1, Family: syscall.AF_INET, Protocol: unix.IPPROTO_UDP,
  2294  	}
  2295  	// Socket connected to backend2
  2296  	s2 := testsockets.MockSocket{
  2297  		SockID: id2, Family: syscall.AF_INET, Protocol: unix.IPPROTO_UDP,
  2298  	}
  2299  	svc := &lb.SVC{
  2300  		Frontend: frontend1,
  2301  		Backends: backends,
  2302  		Name:     lb.ServiceName{Name: "svc1", Namespace: "ns1"},
  2303  	}
  2304  	key1 := *lbmap.NewSockRevNat4Key(1234, s1.SockID.Destination, s1.SockID.DestinationPort)
  2305  	key2 := *lbmap.NewSockRevNat4Key(1235, s2.SockID.Destination, s2.SockID.DestinationPort)
  2306  	m.lbmap.SockRevNat4[key1] = lbmap.SockRevNat4Value{}
  2307  	m.lbmap.SockRevNat4[key2] = lbmap.SockRevNat4Value{}
  2308  	sockets := []*testsockets.MockSocket{&s1, &s2}
  2309  	m.svc.backendConnectionHandler = testsockets.NewMockSockets(sockets)
  2310  
  2311  	created, _, err := m.svc.UpsertService(svc)
  2312  
  2313  	require.Nil(t, err)
  2314  	require.Equal(t, true, created)
  2315  
  2316  	// Delete one of the backends.
  2317  	svc = &lb.SVC{
  2318  		Frontend: frontend1,
  2319  		Backends: []*lb.Backend{backends[1]},
  2320  		Name:     lb.ServiceName{Name: "svc1", Namespace: "ns1"},
  2321  	}
  2322  
  2323  	created, _, err = m.svc.UpsertService(svc)
  2324  
  2325  	require.Nil(t, err)
  2326  	require.Equal(t, false, created)
  2327  
  2328  	// Only the sockets connected to the deleted backend are destroyed.
  2329  	for _, socket := range sockets {
  2330  		if socket.Equal(sockets[0]) {
  2331  			require.Equal(t, true, socket.Destroyed)
  2332  		} else {
  2333  			require.Equal(t, false, socket.Destroyed)
  2334  		}
  2335  	}
  2336  }
  2337  
  2338  type FakeBackendSyncer struct {
  2339  	nrOfBackends int
  2340  	nrOfSyncs    int
  2341  }
  2342  
  2343  var _ BackendSyncer = &FakeBackendSyncer{}
  2344  
  2345  func (r *FakeBackendSyncer) ProxyName() string {
  2346  	return "Fake"
  2347  }
  2348  
  2349  func (r *FakeBackendSyncer) Sync(svc *lb.SVC) error {
  2350  	r.nrOfBackends = len(svc.Backends)
  2351  	r.nrOfSyncs++
  2352  
  2353  	return nil
  2354  }
  2355  
  2356  type FakeMonitorAgent struct{}
  2357  
  2358  var _ monitorAgent.Agent = &FakeMonitorAgent{}
  2359  
  2360  func (f *FakeMonitorAgent) AttachToEventsMap(nPages int) error {
  2361  	return nil
  2362  }
  2363  
  2364  func (f *FakeMonitorAgent) RegisterNewConsumer(newConsumer consumer.MonitorConsumer) {
  2365  }
  2366  
  2367  func (f *FakeMonitorAgent) RegisterNewListener(newListener listener.MonitorListener) {
  2368  }
  2369  
  2370  func (f *FakeMonitorAgent) RemoveConsumer(mc consumer.MonitorConsumer) {
  2371  }
  2372  
  2373  func (f *FakeMonitorAgent) RemoveListener(ml listener.MonitorListener) {
  2374  }
  2375  
  2376  func (f *FakeMonitorAgent) SendEvent(typ int, event interface{}) error {
  2377  	return nil
  2378  }
  2379  
  2380  func (f *FakeMonitorAgent) State() *models.MonitorStatus {
  2381  	return nil
  2382  }