Skip to content

Commit 79c19d0

Browse files
authored
Merge pull request #2461 from suwang48404/master
Allowed libnetwork caller to set ephemeral port
2 parents 90afbb0 + 94facac commit 79c19d0

File tree

6 files changed

+134
-14
lines changed

6 files changed

+134
-14
lines changed

config/config.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package config
22

33
import (
4+
"fmt"
45
"strings"
56

67
"github.com/BurntSushi/toml"
@@ -13,6 +14,7 @@ import (
1314
"github.com/docker/libnetwork/ipamutils"
1415
"github.com/docker/libnetwork/netlabel"
1516
"github.com/docker/libnetwork/osl"
17+
"github.com/docker/libnetwork/portallocator"
1618
"github.com/sirupsen/logrus"
1719
)
1820

@@ -238,6 +240,23 @@ func OptionExperimental(exp bool) Option {
238240
}
239241
}
240242

243+
// OptionDynamicPortRange function returns an option setter for service port allocation range
244+
func OptionDynamicPortRange(in string) Option {
245+
return func(c *Config) {
246+
start, end := 0, 0
247+
if len(in) > 0 {
248+
n, err := fmt.Sscanf(in, "%d-%d", &start, &end)
249+
if n != 2 || err != nil {
250+
logrus.Errorf("Failed to parse range string with err %v", err)
251+
return
252+
}
253+
}
254+
if err := portallocator.Get().SetPortRange(start, end); err != nil {
255+
logrus.Errorf("Failed to set port range with err %v", err)
256+
}
257+
}
258+
}
259+
241260
// OptionNetworkControlPlaneMTU function returns an option setter for control plane MTU
242261
func OptionNetworkControlPlaneMTU(exp int) Option {
243262
return func(c *Config) {

portallocator/portallocator.go

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,36 @@ package portallocator
33
import (
44
"errors"
55
"fmt"
6+
"github.com/sirupsen/logrus"
67
"net"
78
"sync"
89
)
910

10-
const (
11-
// DefaultPortRangeStart indicates the first port in port range
12-
DefaultPortRangeStart = 49153
13-
// DefaultPortRangeEnd indicates the last port in port range
14-
DefaultPortRangeEnd = 65535
11+
var (
12+
// defaultPortRangeStart indicates the first port in port range
13+
defaultPortRangeStart = 49153
14+
// defaultPortRangeEnd indicates the last port in port range
15+
// consistent with default /proc/sys/net/ipv4/ip_local_port_range
16+
// upper bound on linux
17+
defaultPortRangeEnd = 60999
1518
)
1619

20+
func sanitizePortRange(start int, end int) (newStart, newEnd int, err error) {
21+
if start > defaultPortRangeEnd || end < defaultPortRangeStart || start > end {
22+
return 0, 0, fmt.Errorf("Request out allowed range [%v, %v]",
23+
defaultPortRangeStart, defaultPortRangeEnd)
24+
}
25+
err = nil
26+
newStart, newEnd = start, end
27+
if start < defaultPortRangeStart {
28+
newStart = defaultPortRangeStart
29+
}
30+
if end > defaultPortRangeEnd {
31+
newEnd = defaultPortRangeEnd
32+
}
33+
return
34+
}
35+
1736
type ipMapping map[string]protoMap
1837

1938
var (
@@ -92,11 +111,19 @@ func Get() *PortAllocator {
92111
return instance
93112
}
94113

95-
func newInstance() *PortAllocator {
114+
func getDefaultPortRange() (int, int) {
96115
start, end, err := getDynamicPortRange()
116+
if err == nil {
117+
start, end, err = sanitizePortRange(start, end)
118+
}
97119
if err != nil {
98-
start, end = DefaultPortRangeStart, DefaultPortRangeEnd
120+
start, end = defaultPortRangeStart, defaultPortRangeEnd
99121
}
122+
return start, end
123+
}
124+
125+
func newInstance() *PortAllocator {
126+
start, end := getDefaultPortRange()
100127
return &PortAllocator{
101128
ipMap: ipMapping{},
102129
Begin: start,
@@ -170,6 +197,35 @@ func (p *PortAllocator) ReleasePort(ip net.IP, proto string, port int) error {
170197
return nil
171198
}
172199

200+
// SetPortRange sets dynamic port allocation range.
201+
// if both portBegin and portEnd are 0, the port range reverts to default
202+
// value. Otherwise they are sanitized against the default values to
203+
// ensure their validity.
204+
func (p *PortAllocator) SetPortRange(portBegin, portEnd int) error {
205+
// if begin and end is zero, revert to default values
206+
var begin, end int
207+
var err error
208+
if portBegin == 0 && portEnd == 0 {
209+
begin, end = getDefaultPortRange()
210+
211+
} else {
212+
begin, end, err = sanitizePortRange(portBegin, portEnd)
213+
if err != nil {
214+
return err
215+
}
216+
}
217+
logrus.Debugf("Setting up port allocator to range %v-%v, current %v-%v",
218+
begin, end, p.Begin, p.End)
219+
p.mutex.Lock()
220+
defer p.mutex.Unlock()
221+
if p.Begin == begin && p.End == end {
222+
return nil
223+
}
224+
p.ipMap = ipMapping{}
225+
p.Begin, p.End = begin, end
226+
return nil
227+
}
228+
173229
func (p *PortAllocator) newPortMap() *portMap {
174230
defaultKey := getRangeKey(p.Begin, p.End)
175231
pm := &portMap{

portallocator/portallocator_freebsd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88

99
func getDynamicPortRange() (start int, end int, err error) {
1010
portRangeKernelSysctl := []string{"net.inet.ip.portrange.hifirst", "net.ip.portrange.hilast"}
11-
portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", DefaultPortRangeStart, DefaultPortRangeEnd)
11+
portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", defaultPortRangeStart, defaultPortRangeEnd)
1212
portRangeLowCmd := exec.Command("/sbin/sysctl", portRangeKernelSysctl[0])
1313
var portRangeLowOut bytes.Buffer
1414
portRangeLowCmd.Stdout = &portRangeLowOut

portallocator/portallocator_linux.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88

99
func getDynamicPortRange() (start int, end int, err error) {
1010
const portRangeKernelParam = "/proc/sys/net/ipv4/ip_local_port_range"
11-
portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", DefaultPortRangeStart, DefaultPortRangeEnd)
11+
portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", defaultPortRangeStart, defaultPortRangeEnd)
1212
file, err := os.Open(portRangeKernelParam)
1313
if err != nil {
1414
return 0, 0, fmt.Errorf("port allocator - %s due to error: %v", portRangeFallback, err)

portallocator/portallocator_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package portallocator
22

33
import (
4+
"fmt"
45
"net"
56
"testing"
67

@@ -321,3 +322,47 @@ func TestNoDuplicateBPR(t *testing.T) {
321322
t.Fatalf("Acquire(0) allocated the same port twice: %d", port)
322323
}
323324
}
325+
326+
func TestChangePortRange(t *testing.T) {
327+
var tests = []struct {
328+
begin int
329+
end int
330+
setErr error
331+
reqRlt int
332+
}{
333+
{defaultPortRangeEnd + 1, defaultPortRangeEnd + 10, fmt.Errorf("begin out of range"), 0},
334+
{defaultPortRangeStart - 10, defaultPortRangeStart - 1, fmt.Errorf("end out of range"), 0},
335+
{defaultPortRangeEnd, defaultPortRangeStart, fmt.Errorf("out of order"), 0},
336+
{defaultPortRangeStart + 100, defaultPortRangeEnd + 10, nil, defaultPortRangeStart + 100},
337+
{0, 0, nil, defaultPortRangeStart}, // revert to default if no value given
338+
{defaultPortRangeStart - 100, defaultPortRangeEnd, nil, defaultPortRangeStart + 1},
339+
}
340+
p := Get()
341+
port := 0
342+
for _, c := range tests {
343+
t.Logf("test: port allocate range %v-%v, setErr=%v, reqPort=%v",
344+
c.begin, c.end, c.setErr, c.reqRlt)
345+
err := p.SetPortRange(c.begin, c.end)
346+
if (c.setErr == nil && c.setErr != err) ||
347+
(c.setErr != nil && err == nil) {
348+
t.Fatalf("Unexpected set range result, expected=%v, actual=%v", c.setErr, err)
349+
}
350+
if err != nil {
351+
continue
352+
}
353+
if port > 0 {
354+
err := p.ReleasePort(defaultIP, "tcp", port)
355+
if err != nil {
356+
t.Fatalf("Releasing port %v failed, err=%v", port, err)
357+
}
358+
}
359+
360+
port, err = p.RequestPort(defaultIP, "tcp", 0)
361+
if err != nil {
362+
t.Fatalf("Request failed, err %v", err)
363+
}
364+
if port != c.reqRlt {
365+
t.Fatalf("Incorrect port returned, expected=%v, actual=%v", c.reqRlt, port)
366+
}
367+
}
368+
}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package portallocator
22

3-
const (
4-
StartPortRange = 60000
5-
EndPortRange = 65000
6-
)
3+
func init() {
4+
defaultPortRangeStart = 60000
5+
defaultPortRangeEnd = 65000
6+
}
77

88
func getDynamicPortRange() (start int, end int, err error) {
9-
return StartPortRange, EndPortRange, nil
9+
return defaultPortRangeStart, defaultPortRangeEnd, nil
1010
}

0 commit comments

Comments
 (0)