Skip to content

Commit 9fd6c8b

Browse files
committed
add support for IPv6
1 parent da4c8a0 commit 9fd6c8b

File tree

8 files changed

+239
-49
lines changed

8 files changed

+239
-49
lines changed

Diff for: apis/v1alpha1/nginxproxy_types.go

+21
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,33 @@ type NginxProxyList struct {
2727
Items []NginxProxy `json:"items"`
2828
}
2929

30+
// IPFamilyType specifies the IP family to use for all servers.
31+
//
32+
// +kubebuilder:validation:Enum=ipv4;ipv6;both
33+
type IPFamilyType string
34+
35+
const (
36+
// IPv4 specifies that only IPv4 should be used.
37+
IPv4 IPFamilyType = "ipv4"
38+
39+
// IPv6 specifies that only IPv6 should be used.
40+
IPv6 IPFamilyType = "ipv6"
41+
42+
// Both specifies that both IPv4 and IPv6 should be used.
43+
Both IPFamilyType = "both"
44+
)
45+
3046
// NginxProxySpec defines the desired state of the NginxProxy.
3147
type NginxProxySpec struct {
3248
// Telemetry specifies the OpenTelemetry configuration.
3349
//
3450
// +optional
3551
Telemetry *Telemetry `json:"telemetry,omitempty"`
52+
// IPFamily specifies the IP family to use for all servers.
53+
// Default is "both", meaning both IPv4 and IPv6 will be used.
54+
//
55+
// +optional
56+
IPFamily IPFamilyType `json:"ipFamily,omitempty"`
3657
// DisableHTTP2 defines if http2 should be disabled for all servers.
3758
// Default is false, meaning http2 will be enabled for all servers.
3859
//

Diff for: internal/mode/static/nginx/config/http/config.go

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type Server struct {
1010
IsDefaultHTTP bool
1111
IsDefaultSSL bool
1212
GRPC bool
13+
IPv6Enabled bool
1314
}
1415

1516
// Location holds all configuration for an HTTP location.

Diff for: internal/mode/static/nginx/config/servers.go

+32-11
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strings"
99
gotemplate "text/template"
1010

11+
ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
1112
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
1213
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/config/http"
1314
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/dataplane"
@@ -58,7 +59,8 @@ var grpcBaseHeaders = []http.Header{
5859
}
5960

6061
func executeServers(conf dataplane.Configuration) []executeResult {
61-
servers, httpMatchPairs := createServers(conf.HTTPServers, conf.SSLServers)
62+
ipv6Enabled := getIPFamily(conf.BaseHTTPConfig)
63+
servers, httpMatchPairs := createServers(conf.HTTPServers, conf.SSLServers, ipv6Enabled)
6264

6365
serverResult := executeResult{
6466
dest: httpConfigFile,
@@ -86,6 +88,15 @@ func executeServers(conf dataplane.Configuration) []executeResult {
8688
return allResults
8789
}
8890

91+
// getIPFamily returns whether or not the configuration is set to use IPv6.
92+
func getIPFamily(baseHTTPConfig dataplane.BaseHTTPConfig) bool {
93+
if baseHTTPConfig.IPFamily == ngfAPI.IPv6 || baseHTTPConfig.IPFamily == ngfAPI.Both {
94+
return true
95+
}
96+
97+
return false
98+
}
99+
89100
func createAdditionFileResults(conf dataplane.Configuration) []executeResult {
90101
uniqueAdditions := make(map[string][]byte)
91102

@@ -141,17 +152,23 @@ func createIncludes(additions []dataplane.Addition) []string {
141152
return includes
142153
}
143154

144-
func createServers(httpServers, sslServers []dataplane.VirtualServer) ([]http.Server, httpMatchPairs) {
155+
func createServers(
156+
httpServers,
157+
sslServers []dataplane.VirtualServer,
158+
ipv6Enabled bool,
159+
) ([]http.Server, httpMatchPairs) {
145160
servers := make([]http.Server, 0, len(httpServers)+len(sslServers))
146161
finalMatchPairs := make(httpMatchPairs)
147162

148163
for serverID, s := range httpServers {
164+
s.IPv6Enabled = ipv6Enabled
149165
httpServer, matchPairs := createServer(s, serverID)
150166
servers = append(servers, httpServer)
151167
maps.Copy(finalMatchPairs, matchPairs)
152168
}
153169

154170
for serverID, s := range sslServers {
171+
s.IPv6Enabled = ipv6Enabled
155172
sslServer, matchPair := createSSLServer(s, serverID)
156173
servers = append(servers, sslServer)
157174
maps.Copy(finalMatchPairs, matchPair)
@@ -165,6 +182,7 @@ func createSSLServer(virtualServer dataplane.VirtualServer, serverID int) (http.
165182
return http.Server{
166183
IsDefaultSSL: true,
167184
Port: virtualServer.Port,
185+
IPv6Enabled: virtualServer.IPv6Enabled,
168186
}, nil
169187
}
170188

@@ -176,10 +194,11 @@ func createSSLServer(virtualServer dataplane.VirtualServer, serverID int) (http.
176194
Certificate: generatePEMFileName(virtualServer.SSL.KeyPairID),
177195
CertificateKey: generatePEMFileName(virtualServer.SSL.KeyPairID),
178196
},
179-
Locations: locs,
180-
Port: virtualServer.Port,
181-
GRPC: grpc,
182-
Includes: createIncludes(virtualServer.Additions),
197+
Locations: locs,
198+
Port: virtualServer.Port,
199+
GRPC: grpc,
200+
Includes: createIncludes(virtualServer.Additions),
201+
IPv6Enabled: virtualServer.IPv6Enabled,
183202
}, matchPairs
184203
}
185204

@@ -188,17 +207,19 @@ func createServer(virtualServer dataplane.VirtualServer, serverID int) (http.Ser
188207
return http.Server{
189208
IsDefaultHTTP: true,
190209
Port: virtualServer.Port,
210+
IPv6Enabled: virtualServer.IPv6Enabled,
191211
}, nil
192212
}
193213

194214
locs, matchPairs, grpc := createLocations(&virtualServer, serverID)
195215

196216
return http.Server{
197-
ServerName: virtualServer.Hostname,
198-
Locations: locs,
199-
Port: virtualServer.Port,
200-
GRPC: grpc,
201-
Includes: createIncludes(virtualServer.Additions),
217+
ServerName: virtualServer.Hostname,
218+
Locations: locs,
219+
Port: virtualServer.Port,
220+
GRPC: grpc,
221+
Includes: createIncludes(virtualServer.Additions),
222+
IPv6Enabled: virtualServer.IPv6Enabled,
202223
}, matchPairs
203224
}
204225

Diff for: internal/mode/static/nginx/config/servers_template.go

+12
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,18 @@ js_preload_object matches from /etc/nginx/conf.d/matches.json;
66
{{ if $s.IsDefaultSSL -}}
77
server {
88
listen {{ $s.Port }} ssl default_server;
9+
{{- if $s.IPv6Enabled }}
10+
listen [::]:{{ $s.Port }} ssl default_server;
11+
{{- end }}
912
1013
ssl_reject_handshake on;
1114
}
1215
{{- else if $s.IsDefaultHTTP }}
1316
server {
1417
listen {{ $s.Port }} default_server;
18+
{{- if $s.IPv6Enabled }}
19+
listen [::]:{{ $s.Port }} default_server;
20+
{{- end }}
1521
1622
default_type text/html;
1723
return 404;
@@ -20,6 +26,9 @@ server {
2026
server {
2127
{{- if $s.SSL }}
2228
listen {{ $s.Port }} ssl;
29+
{{- if $s.IPv6Enabled }}
30+
listen [::]:{{ $s.Port }} ssl;
31+
{{- end }}
2332
ssl_certificate {{ $s.SSL.Certificate }};
2433
ssl_certificate_key {{ $s.SSL.CertificateKey }};
2534
@@ -28,6 +37,9 @@ server {
2837
}
2938
{{- else }}
3039
listen {{ $s.Port }};
40+
{{- if $s.IPv6Enabled }}
41+
listen [::]:{{ $s.Port }};
42+
{{- end }}
3143
{{- end }}
3244
3345
server_name {{ $s.ServerName }};

Diff for: internal/mode/static/nginx/config/servers_test.go

+34-14
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
. "github.com/onsi/gomega"
1010
"k8s.io/apimachinery/pkg/types"
1111

12+
ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
1213
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/helpers"
1314
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/config/http"
1415
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/dataplane"
@@ -92,13 +93,20 @@ func TestExecuteServers(t *testing.T) {
9293
},
9394
},
9495
},
96+
BaseHTTPConfig: dataplane.BaseHTTPConfig{
97+
IPFamily: ngfAPI.Both,
98+
},
9599
}
96100

97101
expSubStrings := map[string]int{
98102
"listen 8080 default_server;": 1,
103+
"listen [::]:8080 default_server;": 1,
99104
"listen 8080;": 2,
105+
"listen [::]:8080;": 2,
100106
"listen 8443 ssl;": 2,
107+
"listen [::]:8443 ssl;": 2,
101108
"listen 8443 ssl default_server;": 1,
109+
"listen [::]:8443 ssl default_server;": 1,
102110
"server_name example.com;": 2,
103111
"server_name cafe.example.com;": 2,
104112
"ssl_certificate /etc/nginx/secrets/test-keypair.pem;": 2,
@@ -621,8 +629,9 @@ func TestCreateServers(t *testing.T) {
621629

622630
httpServers := []dataplane.VirtualServer{
623631
{
624-
IsDefault: true,
625-
Port: 8080,
632+
IsDefault: true,
633+
Port: 8080,
634+
IPv6Enabled: true,
626635
},
627636
{
628637
Hostname: "cafe.example.com",
@@ -638,13 +647,15 @@ func TestCreateServers(t *testing.T) {
638647
Identifier: "server-addition-2",
639648
},
640649
},
650+
IPv6Enabled: true,
641651
},
642652
}
643653

644654
sslServers := []dataplane.VirtualServer{
645655
{
646-
IsDefault: true,
647-
Port: 8443,
656+
IsDefault: true,
657+
Port: 8443,
658+
IPv6Enabled: true,
648659
},
649660
{
650661
Hostname: "cafe.example.com",
@@ -661,6 +672,7 @@ func TestCreateServers(t *testing.T) {
661672
Identifier: "server-addition-3",
662673
},
663674
},
675+
IPv6Enabled: true,
664676
},
665677
}
666678

@@ -1025,6 +1037,7 @@ func TestCreateServers(t *testing.T) {
10251037
{
10261038
IsDefaultHTTP: true,
10271039
Port: 8080,
1040+
IPv6Enabled: true,
10281041
},
10291042
{
10301043
ServerName: "cafe.example.com",
@@ -1035,10 +1048,12 @@ func TestCreateServers(t *testing.T) {
10351048
includesFolder + "/server-addition-1.conf",
10361049
includesFolder + "/server-addition-2.conf",
10371050
},
1051+
IPv6Enabled: true,
10381052
},
10391053
{
10401054
IsDefaultSSL: true,
10411055
Port: 8443,
1056+
IPv6Enabled: true,
10421057
},
10431058
{
10441059
ServerName: "cafe.example.com",
@@ -1053,12 +1068,13 @@ func TestCreateServers(t *testing.T) {
10531068
includesFolder + "/server-addition-1.conf",
10541069
includesFolder + "/server-addition-3.conf",
10551070
},
1071+
IPv6Enabled: true,
10561072
},
10571073
}
10581074

10591075
g := NewWithT(t)
10601076

1061-
result, httpMatchPair := createServers(httpServers, sslServers)
1077+
result, httpMatchPair := createServers(httpServers, sslServers, true)
10621078

10631079
g.Expect(httpMatchPair).To(Equal(allExpMatchPair))
10641080
g.Expect(helpers.Diff(expectedServers, result)).To(BeEmpty())
@@ -1244,30 +1260,34 @@ func TestCreateServersConflicts(t *testing.T) {
12441260
t.Run(test.name, func(t *testing.T) {
12451261
httpServers := []dataplane.VirtualServer{
12461262
{
1247-
IsDefault: true,
1248-
Port: 8080,
1263+
IsDefault: true,
1264+
Port: 8080,
1265+
IPv6Enabled: true,
12491266
},
12501267
{
1251-
Hostname: "cafe.example.com",
1252-
PathRules: test.rules,
1253-
Port: 8080,
1268+
Hostname: "cafe.example.com",
1269+
PathRules: test.rules,
1270+
Port: 8080,
1271+
IPv6Enabled: true,
12541272
},
12551273
}
12561274
expectedServers := []http.Server{
12571275
{
12581276
IsDefaultHTTP: true,
12591277
Port: 8080,
1278+
IPv6Enabled: true,
12601279
},
12611280
{
1262-
ServerName: "cafe.example.com",
1263-
Locations: test.expLocs,
1264-
Port: 8080,
1281+
ServerName: "cafe.example.com",
1282+
Locations: test.expLocs,
1283+
Port: 8080,
1284+
IPv6Enabled: true,
12651285
},
12661286
}
12671287

12681288
g := NewWithT(t)
12691289

1270-
result, _ := createServers(httpServers, []dataplane.VirtualServer{})
1290+
result, _ := createServers(httpServers, []dataplane.VirtualServer{}, true)
12711291
g.Expect(helpers.Diff(expectedServers, result)).To(BeEmpty())
12721292
})
12731293
}

Diff for: internal/mode/static/state/dataplane/configuration.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,8 @@ func buildTelemetry(g *graph.Graph) Telemetry {
659659
func buildBaseHTTPConfig(g *graph.Graph) BaseHTTPConfig {
660660
baseConfig := BaseHTTPConfig{
661661
// HTTP2 should be enabled by default
662-
HTTP2: true,
662+
HTTP2: true,
663+
IPFamily: ngfAPI.Both,
663664
}
664665
if g.NginxProxy == nil || !g.NginxProxy.Valid {
665666
return baseConfig
@@ -669,6 +670,15 @@ func buildBaseHTTPConfig(g *graph.Graph) BaseHTTPConfig {
669670
baseConfig.HTTP2 = false
670671
}
671672

673+
switch ipType := g.NginxProxy.Source.Spec.IPFamily; ipType {
674+
case ngfAPI.IPv4:
675+
baseConfig.IPFamily = ngfAPI.IPv4
676+
case ngfAPI.IPv6:
677+
baseConfig.IPFamily = ngfAPI.IPv6
678+
case ngfAPI.Both:
679+
baseConfig.IPFamily = ngfAPI.Both
680+
}
681+
672682
return baseConfig
673683
}
674684

0 commit comments

Comments
 (0)