Skip to content

Commit 578bfde

Browse files
authored
Merge pull request #132 from thaJeztah/optimize_ParsePortSpec
nat: ParsePortSpecs: reduce allocations and improve performance
2 parents fbf5d1f + 30b91c8 commit 578bfde

File tree

2 files changed

+47
-25
lines changed

2 files changed

+47
-25
lines changed

nat/nat.go

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -198,42 +198,39 @@ func ParsePortSpec(rawPort string) ([]PortMapping, error) {
198198
return nil, errors.New("invalid containerPort: " + containerPort)
199199
}
200200

201-
var startHostPort, endHostPort uint64 = 0, 0
201+
var startHostPort, endHostPort uint64
202202
if hostPort != "" {
203203
startHostPort, endHostPort, err = ParsePortRange(hostPort)
204204
if err != nil {
205205
return nil, errors.New("invalid hostPort: " + hostPort)
206206
}
207-
}
208-
209-
if hostPort != "" && (endPort-startPort) != (endHostPort-startHostPort) {
210-
// Allow host port range iff containerPort is not a range.
211-
// In this case, use the host port range as the dynamic
212-
// host port range to allocate into.
213-
if endPort != startPort {
214-
return nil, fmt.Errorf("invalid ranges specified for container and host Ports: %s and %s", containerPort, hostPort)
207+
if (endPort - startPort) != (endHostPort - startHostPort) {
208+
// Allow host port range iff containerPort is not a range.
209+
// In this case, use the host port range as the dynamic
210+
// host port range to allocate into.
211+
if endPort != startPort {
212+
return nil, fmt.Errorf("invalid ranges specified for container and host Ports: %s and %s", containerPort, hostPort)
213+
}
215214
}
216215
}
217216

218-
ports := []PortMapping{}
219-
for i := uint64(0); i <= (endPort - startPort); i++ {
220-
containerPort = strconv.FormatUint(startPort+i, 10)
217+
count := endPort - startPort + 1
218+
ports := make([]PortMapping, 0, count)
219+
220+
for i := uint64(0); i < count; i++ {
221+
cPort := Port(strconv.FormatUint(startPort+i, 10) + "/" + proto)
222+
hPort := ""
221223
if hostPort != "" {
222-
hostPort = strconv.FormatUint(startHostPort+i, 10)
223-
}
224-
// Set hostPort to a range only if there is a single container port
225-
// and a dynamic host port.
226-
if startPort == endPort && startHostPort != endHostPort {
227-
hostPort = hostPort + "-" + strconv.FormatUint(endHostPort, 10)
228-
}
229-
port, err := NewPort(proto, containerPort)
230-
if err != nil {
231-
return nil, err
224+
hPort = strconv.FormatUint(startHostPort+i, 10)
225+
// Set hostPort to a range only if there is a single container port
226+
// and a dynamic host port.
227+
if count == 1 && startHostPort != endHostPort {
228+
hPort += "-" + strconv.FormatUint(endHostPort, 10)
229+
}
232230
}
233-
234231
ports = append(ports, PortMapping{
235-
Port: port,
236-
Binding: PortBinding{HostIP: ip, HostPort: hostPort},
232+
Port: cPort,
233+
Binding: PortBinding{HostIP: ip, HostPort: hPort},
237234
})
238235
}
239236
return ports, nil

nat/nat_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,3 +841,28 @@ func TestStringer(t *testing.T) {
841841
})
842842
}
843843
}
844+
845+
func BenchmarkParsePortSpecs(b *testing.B) {
846+
specs := [][]string{
847+
{"1234/tcp", "2345/udp", "3456/sctp"},
848+
{"1234:1234/tcp", "2345:2345/udp", "3456:3456/sctp"},
849+
{"0.0.0.0:1234:1234/tcp", "0.0.0.0:2345:2345/udp", "0.0.0.0:3456:3456/sctp"},
850+
{"1234-1236/tcp", "2345-2347/udp", "3456-3458/sctp"},
851+
{"1234-1236:1234-1236/tcp", "2345-2347:2345-2347/udp", "3456-3458:3456-3458/sctp"},
852+
{"0.0.0.0:1234-1236:1234-1236/tcp", "0.0.0.0:2345-2347:2345-2347/udp", "0.0.0.0:3456-3458:3456-3458/sctp"},
853+
{"[2001:4860:0:2001::68]::333"},
854+
{"[::1]:80:80"},
855+
{"::1:80:80"},
856+
{"::::80"},
857+
}
858+
859+
b.ReportAllocs()
860+
b.ResetTimer()
861+
for i := 0; i < b.N; i++ {
862+
for _, group := range specs {
863+
if _, _, err := ParsePortSpecs(group); err != nil {
864+
b.Fatalf("unexpected error: %v", err)
865+
}
866+
}
867+
}
868+
}

0 commit comments

Comments
 (0)