mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
cd2b019214
prioritize the ports with static mapping before dynamic mapping. This removes the port conflicts when we allocate static port in the reserved range together with dynamic ones. When static port is allocated first, Docker will skip those when determining free ports for dynamic ones. Signed-off-by: Daniel, Dao Quang Minh <dqminh89@gmail.com>
92 lines
1.9 KiB
Go
92 lines
1.9 KiB
Go
package nat
|
|
|
|
import (
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type portSorter struct {
|
|
ports []Port
|
|
by func(i, j Port) bool
|
|
}
|
|
|
|
func (s *portSorter) Len() int {
|
|
return len(s.ports)
|
|
}
|
|
|
|
func (s *portSorter) Swap(i, j int) {
|
|
s.ports[i], s.ports[j] = s.ports[j], s.ports[i]
|
|
}
|
|
|
|
func (s *portSorter) Less(i, j int) bool {
|
|
ip := s.ports[i]
|
|
jp := s.ports[j]
|
|
|
|
return s.by(ip, jp)
|
|
}
|
|
|
|
func Sort(ports []Port, predicate func(i, j Port) bool) {
|
|
s := &portSorter{ports, predicate}
|
|
sort.Sort(s)
|
|
}
|
|
|
|
type portMapEntry struct {
|
|
port Port
|
|
binding PortBinding
|
|
}
|
|
|
|
type portMapSorter []portMapEntry
|
|
|
|
func (s portMapSorter) Len() int { return len(s) }
|
|
func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
|
|
// sort the port so that the order is:
|
|
// 1. port with larger specified bindings
|
|
// 2. larger port
|
|
// 3. port with tcp protocol
|
|
func (s portMapSorter) Less(i, j int) bool {
|
|
pi, pj := s[i].port, s[j].port
|
|
hpi, hpj := toInt(s[i].binding.HostPort), toInt(s[j].binding.HostPort)
|
|
return hpi > hpj || pi.Int() > pj.Int() || (pi.Int() == pj.Int() && strings.ToLower(pi.Proto()) == "tcp")
|
|
}
|
|
|
|
// SortPortMap sorts the list of ports and their respected mapping. The ports
|
|
// will explicit HostPort will be placed first.
|
|
func SortPortMap(ports []Port, bindings PortMap) {
|
|
s := portMapSorter{}
|
|
for _, p := range ports {
|
|
if binding, ok := bindings[p]; ok {
|
|
for _, b := range binding {
|
|
s = append(s, portMapEntry{port: p, binding: b})
|
|
}
|
|
} else {
|
|
s = append(s, portMapEntry{port: p})
|
|
}
|
|
bindings[p] = []PortBinding{}
|
|
}
|
|
|
|
sort.Sort(s)
|
|
var (
|
|
i int
|
|
pm = make(map[Port]struct{})
|
|
)
|
|
// reorder ports
|
|
for _, entry := range s {
|
|
if _, ok := pm[entry.port]; !ok {
|
|
ports[i] = entry.port
|
|
pm[entry.port] = struct{}{}
|
|
i++
|
|
}
|
|
// reorder bindings for this port
|
|
bindings[entry.port] = append(bindings[entry.port], entry.binding)
|
|
}
|
|
}
|
|
|
|
func toInt(s string) int64 {
|
|
i, err := strconv.ParseInt(s, 10, 64)
|
|
if err != nil {
|
|
i = 0
|
|
}
|
|
return i
|
|
}
|