Skip to content

Commit dbbc214

Browse files
WIP L3 NetLB experiment
1 parent 203252b commit dbbc214

File tree

7 files changed

+96
-26
lines changed

7 files changed

+96
-26
lines changed

pkg/flags/flags.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ var F = struct {
148148
ManageL4LBLogging bool
149149
EnableNEGsForIngress bool
150150
EnableIPv6OnlyL4 bool
151+
EnableL3NetLBOptIn bool
151152
L4ILBLegacyHeadStartTime time.Duration
152153

153154
// ===============================
@@ -361,6 +362,7 @@ L7 load balancing. CSV values accepted. Example: -node-port-ranges=80,8080,400-5
361362
flag.BoolVar(&F.ReadOnlyMode, "read-only-controllers", false, "When enabled, this flag runs the IG, NEG, L4 ILB, and L4 NetLB controllers in a read-only mode. This prevents them from executing any mutating API calls (e.g., create, update, delete), allowing you to safely observe controller behavior without modifying resources. The Ingress controller is exempt from this mode.")
362363
flag.BoolVar(&F.EnableNEGsForIngress, "enable-negs-for-ingress", true, "Allow the NEG controller to create NEGs for Ingress services.")
363364
flag.BoolVar(&F.EnableIPv6OnlyL4, "enable-ipv6-only-l4", false, "Enables IPv6-only mode for the L4 ILB and NetLB controllers, disabling all IPv4-related logic and resource management.")
365+
flag.BoolVar(&F.EnableL3NetLBOptIn, "enable-l3-netlb-opt-in", false, "Enables L3 opt in mode for NetLB, where it uses L3 Forwarding Rule and Backend Service regardless of the service spec.")
364366
flag.DurationVar(&F.L4ILBLegacyHeadStartTime, "prevent-legacy-race-l4-ilb", 0*time.Second, "Delay before processing new L4 ILB services without existing finalizers. This gives the legacy controller a head start to claim the service, preventing a race condition upon service creation.")
365367
}
366368

pkg/forwardingrules/equal.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func EqualIPv4(fr1, fr2 *composite.ForwardingRule) (bool, error) {
2323
return false, fmt.Errorf("Equal(): failed to parse backend resource URL from wanted FR, err - %w", err)
2424
}
2525
return fr1.IPAddress == fr2.IPAddress &&
26-
strings.ToLower(fr1.IPProtocol) == strings.ToLower(fr2.IPProtocol) &&
26+
strings.EqualFold(fr1.IPProtocol, fr2.IPProtocol) &&
2727
fr1.LoadBalancingScheme == fr2.LoadBalancingScheme &&
2828
equalPorts(fr1.Ports, fr2.Ports, fr1.PortRange, fr2.PortRange) &&
2929
utils.EqualCloudResourceIDs(id1, id2) &&
@@ -45,7 +45,7 @@ func EqualIPv6(fr1, fr2 *composite.ForwardingRule) (bool, error) {
4545
if err != nil {
4646
return false, fmt.Errorf("EqualIPv6(): failed to parse resource URL from FR, err - %w", err)
4747
}
48-
return strings.ToLower(fr1.IPProtocol) == strings.ToLower(fr2.IPProtocol) &&
48+
return strings.EqualFold(fr1.IPProtocol, fr2.IPProtocol) &&
4949
fr1.LoadBalancingScheme == fr2.LoadBalancingScheme &&
5050
equalPorts(fr1.Ports, fr2.Ports, fr1.PortRange, fr2.PortRange) &&
5151
utils.EqualCloudResourceIDs(id1, id2) &&

pkg/loadbalancers/forwarding_rules.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"k8s.io/ingress-gce/pkg/events"
3636
"k8s.io/ingress-gce/pkg/flags"
3737
"k8s.io/ingress-gce/pkg/forwardingrules"
38+
"k8s.io/ingress-gce/pkg/loadbalancers/l3"
3839
"k8s.io/ingress-gce/pkg/translator"
3940
"k8s.io/ingress-gce/pkg/utils"
4041
"k8s.io/ingress-gce/pkg/utils/namer"
@@ -407,6 +408,12 @@ func (l4netlb *L4NetLB) ensureIPv4ForwardingRule(bsLink string) (*composite.Forw
407408
newFwdRule.PortRange = ""
408409
}
409410

411+
if l3.Wants(l4netlb.Service) {
412+
newFwdRule.Ports, newFwdRule.PortRange = nil, ""
413+
newFwdRule.AllPorts = true
414+
newFwdRule.IPProtocol = forwardingrules.ProtocolL3
415+
}
416+
410417
if existingFwdRule != nil {
411418
if existingFwdRule.NetworkTier != newFwdRule.NetworkTier {
412419
resource := fmt.Sprintf("Forwarding rule (%v)", frName)

pkg/loadbalancers/forwarding_rules_ipv6.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"k8s.io/ingress-gce/pkg/events"
3434
"k8s.io/ingress-gce/pkg/flags"
3535
"k8s.io/ingress-gce/pkg/forwardingrules"
36+
"k8s.io/ingress-gce/pkg/loadbalancers/l3"
3637
"k8s.io/ingress-gce/pkg/utils"
3738
)
3839

@@ -291,6 +292,11 @@ func (l4netlb *L4NetLB) buildExpectedIPv6ForwardingRule(bsLink, ipv6AddressToUse
291292
fr.Ports = utils.GetPorts(svcPorts)
292293
fr.PortRange = ""
293294
}
295+
if l3.Wants(l4netlb.Service) {
296+
fr.Ports, fr.PortRange = nil, ""
297+
fr.AllPorts = true
298+
fr.IPProtocol = forwardingrules.ProtocolL3
299+
}
294300

295301
return fr, nil
296302
}

pkg/loadbalancers/l3/wants.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package l3
2+
3+
import (
4+
corev1 "k8s.io/api/core/v1"
5+
"k8s.io/ingress-gce/pkg/flags"
6+
)
7+
8+
const ExperimentAnnotation = "networking.gke.io/l3-experiment"
9+
10+
func Wants(svc *corev1.Service) bool {
11+
if !flags.F.EnableL3NetLBOptIn {
12+
return false
13+
}
14+
15+
acceptableValues := map[string]struct{}{
16+
"true": {}, "enabled": {}, "enable": {},
17+
"on": {}, "yes": {}, "True": {},
18+
}
19+
20+
val, ok := svc.Annotations[ExperimentAnnotation]
21+
if !ok {
22+
return false
23+
}
24+
_, ok = acceptableValues[val]
25+
return ok
26+
}

pkg/loadbalancers/l4netlb.go

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
"k8s.io/ingress-gce/pkg/forwardingrules"
3939
"k8s.io/ingress-gce/pkg/healthchecksl4"
4040
"k8s.io/ingress-gce/pkg/l4lb/metrics"
41+
"k8s.io/ingress-gce/pkg/loadbalancers/l3"
4142
"k8s.io/ingress-gce/pkg/network"
4243
"k8s.io/ingress-gce/pkg/utils"
4344
"k8s.io/ingress-gce/pkg/utils/namer"
@@ -353,11 +354,6 @@ func (l4netlb *L4NetLB) provideBackendService(syncResult *L4NetLBSyncResult, hcL
353354
bsName := l4netlb.namer.L4Backend(l4netlb.Service.Namespace, l4netlb.Service.Name)
354355
servicePorts := l4netlb.Service.Spec.Ports
355356

356-
protocol := string(utils.GetProtocol(servicePorts))
357-
if l4netlb.enableMixedProtocol {
358-
protocol = backends.GetProtocol(servicePorts)
359-
}
360-
361357
localityLbPolicy := l4netlb.determineBackendServiceLocalityPolicy()
362358

363359
connectionTrackingPolicy := l4netlb.connectionTrackingPolicy()
@@ -376,7 +372,7 @@ func (l4netlb *L4NetLB) provideBackendService(syncResult *L4NetLBSyncResult, hcL
376372
backendParams := backends.L4BackendServiceParams{
377373
Name: bsName,
378374
HealthCheckLink: hcLink,
379-
Protocol: protocol,
375+
Protocol: l4netlb.backendProtocol(servicePorts),
380376
SessionAffinity: string(l4netlb.Service.Spec.SessionAffinity),
381377
Scheme: string(cloud.SchemeExternal),
382378
NamespacedName: l4netlb.NamespacedName,
@@ -405,6 +401,17 @@ func (l4netlb *L4NetLB) provideBackendService(syncResult *L4NetLBSyncResult, hcL
405401
return bs.SelfLink
406402
}
407403

404+
func (l4netlb *L4NetLB) backendProtocol(servicePorts []corev1.ServicePort) string {
405+
switch {
406+
case l3.Wants(l4netlb.Service):
407+
return backends.ProtocolL3
408+
case l4netlb.enableMixedProtocol:
409+
return backends.GetProtocol(servicePorts)
410+
default:
411+
return string(utils.GetProtocol(servicePorts))
412+
}
413+
}
414+
408415
func (l4netlb *L4NetLB) ensureDualStackResources(result *L4NetLBSyncResult, nodeNames []string, bsLink string) {
409416
if utils.NeedsIPv4(l4netlb.Service) {
410417
l4netlb.ensureIPv4Resources(result, nodeNames, bsLink)
@@ -422,7 +429,7 @@ func (l4netlb *L4NetLB) ensureDualStackResources(result *L4NetLBSyncResult, node
422429
// - IPv4 Forwarding Rule
423430
// - IPv4 Firewall
424431
func (l4netlb *L4NetLB) ensureIPv4Resources(result *L4NetLBSyncResult, nodeNames []string, bsLink string) {
425-
if l4netlb.enableMixedProtocol && forwardingrules.NeedsMixed(l4netlb.Service.Spec.Ports) {
432+
if !l3.Wants(l4netlb.Service) && l4netlb.enableMixedProtocol && forwardingrules.NeedsMixed(l4netlb.Service.Spec.Ports) {
426433
l4netlb.ensureIPv4MixedResources(result, nodeNames, bsLink)
427434
return
428435
}
@@ -436,11 +443,7 @@ func (l4netlb *L4NetLB) ensureIPv4Resources(result *L4NetLBSyncResult, nodeNames
436443
result.MetricsLegacyState.IsUserError = IsUserError(err)
437444
return
438445
}
439-
if fr.IPProtocol == string(corev1.ProtocolTCP) {
440-
result.Annotations[annotations.TCPForwardingRuleKey] = fr.Name
441-
} else {
442-
result.Annotations[annotations.UDPForwardingRuleKey] = fr.Name
443-
}
446+
result.Annotations[forwardingRuleAnnotationKey(fr)] = fr.Name
444447
result.MetricsLegacyState.IsManagedIP = ipAddrType == address.IPAddrManaged
445448
result.MetricsLegacyState.IsPremiumTier = fr.NetworkTier == cloud.NetworkTierPremium.ToGCEValue()
446449

@@ -453,6 +456,33 @@ func (l4netlb *L4NetLB) ensureIPv4Resources(result *L4NetLBSyncResult, nodeNames
453456
result.Status = utils.AddIPToLBStatus(result.Status, fr.IPAddress)
454457
}
455458

459+
func forwardingRuleAnnotationKey(fr *composite.ForwardingRule) string {
460+
m := map[string]map[string]string{
461+
"IPV4": {
462+
forwardingrules.ProtocolL3: annotations.L3ForwardingRuleKey,
463+
forwardingrules.ProtocolTCP: annotations.TCPForwardingRuleKey,
464+
forwardingrules.ProtocolUDP: annotations.UDPForwardingRuleKey,
465+
},
466+
"IPV6": {
467+
forwardingrules.ProtocolL3: annotations.L3ForwardingRuleIPv6Key,
468+
forwardingrules.ProtocolTCP: annotations.TCPForwardingRuleIPv6Key,
469+
forwardingrules.ProtocolUDP: annotations.UDPForwardingRuleIPv6Key,
470+
},
471+
}
472+
473+
version := fr.IpVersion
474+
if version == "" {
475+
version = "IPV4"
476+
}
477+
478+
protocol := fr.IPProtocol
479+
if protocol == "" {
480+
protocol = "UDP"
481+
}
482+
483+
return m[version][protocol]
484+
}
485+
456486
func (l4netlb *L4NetLB) ensureIPv4MixedResources(result *L4NetLBSyncResult, nodeNames []string, bsLink string) {
457487
res, err := l4netlb.mixedManager.EnsureIPv4(bsLink)
458488

pkg/loadbalancers/l4netlbipv6.go

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud"
2525
"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
2626
compute "google.golang.org/api/compute/v1"
27-
corev1 "k8s.io/api/core/v1"
2827
"k8s.io/ingress-gce/pkg/annotations"
2928
"k8s.io/ingress-gce/pkg/firewalls"
3029
"k8s.io/ingress-gce/pkg/utils"
@@ -50,11 +49,7 @@ func (l4netlb *L4NetLB) ensureIPv6Resources(syncResult *L4NetLBSyncResult, nodeN
5049
return
5150
}
5251

53-
if ipv6fr.IPProtocol == string(corev1.ProtocolTCP) {
54-
syncResult.Annotations[annotations.TCPForwardingRuleIPv6Key] = ipv6fr.Name
55-
} else {
56-
syncResult.Annotations[annotations.UDPForwardingRuleIPv6Key] = ipv6fr.Name
57-
}
52+
syncResult.Annotations[forwardingRuleAnnotationKey(ipv6fr)] = ipv6fr.Name
5853

5954
// Google Cloud creates ipv6 forwarding rules with IPAddress in CIDR form. We will take only first address
6055
trimmedIPv6Address := strings.Split(ipv6fr.IPAddress, "/")[0]
@@ -120,6 +115,15 @@ func (l4netlb *L4NetLB) ensureIPv6NodesFirewall(ipAddress string, nodeNames []st
120115
svcPorts := l4netlb.Service.Spec.Ports
121116
portRanges := utils.GetServicePortRanges(svcPorts)
122117
protocol := utils.GetProtocol(svcPorts)
118+
allowed := []*compute.FirewallAllowed{
119+
{
120+
IPProtocol: string(protocol),
121+
Ports: portRanges,
122+
},
123+
}
124+
if l4netlb.enableMixedProtocol {
125+
allowed = firewalls.AllowedForService(svcPorts)
126+
}
123127

124128
fwLogger := l4netlb.svcLogger.WithValues("firewallName", firewallName)
125129
fwLogger.V(2).Info("Ensuring IPv6 nodes firewall for L4 NetLB Service", "ipAddress", ipAddress, "protocol", protocol, "len(nodeNames)", len(nodeNames), "portRanges", portRanges)
@@ -135,12 +139,7 @@ func (l4netlb *L4NetLB) ensureIPv6NodesFirewall(ipAddress string, nodeNames []st
135139
}
136140

137141
ipv6nodesFWRParams := firewalls.FirewallParams{
138-
Allowed: []*compute.FirewallAllowed{
139-
{
140-
IPProtocol: string(protocol),
141-
Ports: portRanges,
142-
},
143-
},
142+
Allowed: allowed,
144143
SourceRanges: ipv6SourceRanges,
145144
DestinationRanges: []string{ipAddress},
146145
Name: firewallName,

0 commit comments

Comments
 (0)