Skip to content

Commit

Permalink
Merge pull request #2089 from sawsa307/add-ipv6-service-validation
Browse files Browse the repository at this point in the history
Add validation for ipv6 only service
  • Loading branch information
k8s-ci-robot authored Apr 27, 2023
2 parents ccc9f70 + 26707a3 commit 6604c14
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 0 deletions.
15 changes: 15 additions & 0 deletions pkg/neg/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,10 @@ func (c *Controller) processService(key string) error {
if service == nil {
return fmt.Errorf("cannot convert to Service (%T)", obj)
}
// TODO(cheungdavid): Remove this validation when single stack ipv6 endpoint is supported
if service.Spec.Type != apiv1.ServiceTypeLoadBalancer && isSingleStackIPv6Service(service) {
return fmt.Errorf("NEG is not supported for ipv6 only service (%T)", service)
}
negUsage := usageMetrics.NegServiceState{}
svcPortInfoMap := make(negtypes.PortInfoMap)
networkInfo, err := network.ServiceNetwork(service, c.cloud)
Expand Down Expand Up @@ -848,3 +852,14 @@ func gatherPortMappingFromService(svc *apiv1.Service) negtypes.SvcPortTupleSet {
}
return svcPortTupleSet
}

// isSingleStackIPv6Service returns true if the given service is a single stack ipv6 service
func isSingleStackIPv6Service(service *apiv1.Service) bool {
if service.Spec.IPFamilyPolicy != nil && *service.Spec.IPFamilyPolicy != apiv1.IPFamilyPolicySingleStack {
return false
}
if len(service.Spec.IPFamilies) == 1 && service.Spec.IPFamilies[0] == apiv1.IPv6Protocol {
return true
}
return false
}
106 changes: 106 additions & 0 deletions pkg/neg/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,112 @@ func TestEnqueueEndpoints(t *testing.T) {
}
}

func TestServiceIPFamilies(t *testing.T) {
t.Parallel()
singleStack := apiv1.IPFamilyPolicySingleStack
preferDualStack := apiv1.IPFamilyPolicyPreferDualStack
requireDualStack := apiv1.IPFamilyPolicyRequireDualStack
testCases := []struct {
desc string
serviceType v1.ServiceType
ipFamilies []v1.IPFamily
ipFamilyPolicy *apiv1.IPFamilyPolicy
expectNil bool
}{
{
desc: "ipv6 only service with l7 load balancer, ipFamilyPolicy is singleStack",
serviceType: v1.ServiceTypeClusterIP,
ipFamilies: []v1.IPFamily{v1.IPv6Protocol},
ipFamilyPolicy: &singleStack,
expectNil: false,
},
{
desc: "ipv4 only service with l7 load balancer, ipFamilyPolicy is singleStack",
serviceType: v1.ServiceTypeClusterIP,
ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
ipFamilyPolicy: &singleStack,
expectNil: true,
},
{
desc: "ipv4 service with l7 load balancer, ipFamilyPolicy is preferDualStack",
serviceType: v1.ServiceTypeClusterIP,
ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
ipFamilyPolicy: &preferDualStack,
expectNil: true,
},
{
desc: "dual stack service with l7 load balancer, ipFamilyPolicy is preferDualStack",
serviceType: v1.ServiceTypeClusterIP,
ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
ipFamilyPolicy: &preferDualStack,
expectNil: true,
},
{
desc: "dual stack service with l7 load balancer, ipFamilyPolicy is requiredDualStack",
serviceType: v1.ServiceTypeClusterIP,
ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
ipFamilyPolicy: &requireDualStack,
expectNil: true,
},
{
desc: "ipv6 only service with l4 load balancer, ipFamilyPolicy is singleStack",
serviceType: v1.ServiceTypeLoadBalancer,
ipFamilies: []v1.IPFamily{v1.IPv6Protocol},
ipFamilyPolicy: &singleStack, // single stack ipv6 is supported for l4 load balancer
expectNil: true,
},
{
desc: "ipv4 only service with l4 load balancer, ipFamilyPolicy is singleStack",
serviceType: v1.ServiceTypeLoadBalancer,
ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
ipFamilyPolicy: &singleStack,
expectNil: true,
},
{
desc: "ipv4 only service with l4 load balancer, ipFamilyPolicy is preferDualStack",
serviceType: v1.ServiceTypeLoadBalancer,
ipFamilies: []v1.IPFamily{v1.IPv4Protocol},
ipFamilyPolicy: &preferDualStack,
expectNil: true,
},
{
desc: "dual stack service with l4 load balancer, ipFamilyPolicy is preferDualStack",
serviceType: v1.ServiceTypeLoadBalancer,
ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
ipFamilyPolicy: &preferDualStack,
expectNil: true,
},
{
desc: "dual stack service with l4 load balancer, ipFamilyPolicy is requireDualStack",
serviceType: v1.ServiceTypeLoadBalancer,
ipFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
ipFamilyPolicy: &requireDualStack,
expectNil: true,
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
controller := newTestController(fake.NewSimpleClientset())
defer controller.stop()
testService := newTestService(controller, false, []int32{})
testService.Spec.Type = tc.serviceType
testService.Spec.IPFamilies = tc.ipFamilies
testService.Spec.IPFamilyPolicy = tc.ipFamilyPolicy
controller.serviceLister.Add(testService)
controller.ingressLister.Add(newTestIngress(testServiceName))
svcKey := utils.ServiceKeyFunc(testServiceNamespace, testServiceName)
err := controller.processService(svcKey)
if tc.expectNil && err != nil {
t.Fatalf("Expecting nil when processing type %v service with ipFamily %v, got error %v", tc.serviceType, tc.ipFamilies, err)
}
if !tc.expectNil && err == nil {
t.Fatalf("Expecting error when processing type %v service with ipFamily %v, got nil", tc.serviceType, tc.ipFamilies)
}
})
}

}

func getEvent(eventChan chan string, queue *workqueue.RateLimitingInterface) {
item, quit := (*queue).Get()
if quit {
Expand Down

0 comments on commit 6604c14

Please sign in to comment.