mirror of
https://github.com/containers/podman.git
synced 2025-06-21 01:19:15 +08:00
Update libnetwork vendor to current master to fix CI
Avoid a Sirupsen vs sirupsen class for logrus by updating to master. Signed-off-by: Matthew Heon <matthew.heon@gmail.com>
This commit is contained in:
@ -97,4 +97,4 @@ github.com/openshift/imagebuilder master
|
||||
github.com/ulikunitz/xz v0.5.4
|
||||
github.com/mailru/easyjson 03f2033d19d5860aef995fe360ac7d395cd8ce65
|
||||
github.com/coreos/go-iptables 25d087f3cffd9aedc0c2b7eff25f23cbf3c20fe1
|
||||
github.com/docker/libnetwork v0.7.2-rc.1
|
||||
github.com/docker/libnetwork 20461b8539336a4b5fcf551a86dd24ebae211984
|
||||
|
15
vendor/github.com/docker/libnetwork/README.md
generated
vendored
15
vendor/github.com/docker/libnetwork/README.md
generated
vendored
@ -1,6 +1,6 @@
|
||||
# libnetwork - networking for containers
|
||||
|
||||
[](https://circleci.com/gh/docker/libnetwork/tree/master) [](https://coveralls.io/r/docker/libnetwork) [](https://godoc.org/github.com/docker/libnetwork)
|
||||
[](https://circleci.com/gh/docker/libnetwork/tree/master) [](https://coveralls.io/r/docker/libnetwork) [](https://godoc.org/github.com/docker/libnetwork) [](https://goreportcard.com/report/github.com/docker/libnetwork)
|
||||
|
||||
Libnetwork provides a native Go implementation for connecting containers
|
||||
|
||||
@ -15,6 +15,17 @@ There are many networking solutions available to suit a broad range of use-cases
|
||||
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/config"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/options"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if reexec.Init() {
|
||||
return
|
||||
@ -34,7 +45,7 @@ func main() {
|
||||
|
||||
// Create a network for containers to join.
|
||||
// NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can use.
|
||||
network, err := controller.NewNetwork(networkType, "network1")
|
||||
network, err := controller.NewNetwork(networkType, "network1", "")
|
||||
if err != nil {
|
||||
log.Fatalf("controller.NewNetwork: %s", err)
|
||||
}
|
||||
|
135
vendor/github.com/docker/libnetwork/ipamutils/utils.go
generated
vendored
Normal file
135
vendor/github.com/docker/libnetwork/ipamutils/utils.go
generated
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
// Package ipamutils provides utility functions for ipam management
|
||||
package ipamutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
// PredefinedLocalScopeDefaultNetworks contains a list of 31 IPv4 private networks with host size 16 and 12
|
||||
// (172.17-31.x.x/16, 192.168.x.x/20) which do not overlap with the networks in `PredefinedGlobalScopeDefaultNetworks`
|
||||
PredefinedLocalScopeDefaultNetworks []*net.IPNet
|
||||
// PredefinedGlobalScopeDefaultNetworks contains a list of 64K IPv4 private networks with host size 8
|
||||
// (10.x.x.x/24) which do not overlap with the networks in `PredefinedLocalScopeDefaultNetworks`
|
||||
PredefinedGlobalScopeDefaultNetworks []*net.IPNet
|
||||
mutex sync.Mutex
|
||||
localScopeDefaultNetworks = []*NetworkToSplit{{"172.17.0.0/16", 16}, {"172.18.0.0/16", 16}, {"172.19.0.0/16", 16},
|
||||
{"172.20.0.0/14", 16}, {"172.24.0.0/14", 16}, {"172.28.0.0/14", 16},
|
||||
{"192.168.0.0/16", 20}}
|
||||
globalScopeDefaultNetworks = []*NetworkToSplit{{"10.0.0.0/8", 24}}
|
||||
)
|
||||
|
||||
// NetworkToSplit represent a network that has to be split in chunks with mask length Size.
|
||||
// Each subnet in the set is derived from the Base pool. Base is to be passed
|
||||
// in CIDR format.
|
||||
// Example: a Base "10.10.0.0/16 with Size 24 will define the set of 256
|
||||
// 10.10.[0-255].0/24 address pools
|
||||
type NetworkToSplit struct {
|
||||
Base string `json:"base"`
|
||||
Size int `json:"size"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
if PredefinedGlobalScopeDefaultNetworks, err = splitNetworks(globalScopeDefaultNetworks); err != nil {
|
||||
//we are going to panic in case of error as we should never get into this state
|
||||
panic("InitAddressPools failed to initialize the global scope default address pool")
|
||||
}
|
||||
|
||||
if PredefinedLocalScopeDefaultNetworks, err = splitNetworks(localScopeDefaultNetworks); err != nil {
|
||||
//we are going to panic in case of error as we should never get into this state
|
||||
panic("InitAddressPools failed to initialize the local scope default address pool")
|
||||
}
|
||||
}
|
||||
|
||||
// configDefaultNetworks configures local as well global default pool based on input
|
||||
func configDefaultNetworks(defaultAddressPool []*NetworkToSplit, result *[]*net.IPNet) error {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
defaultNetworks, err := splitNetworks(defaultAddressPool)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*result = defaultNetworks
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetGlobalScopeDefaultNetworks returns PredefinedGlobalScopeDefaultNetworks
|
||||
func GetGlobalScopeDefaultNetworks() []*net.IPNet {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
return PredefinedGlobalScopeDefaultNetworks
|
||||
}
|
||||
|
||||
// GetLocalScopeDefaultNetworks returns PredefinedLocalScopeDefaultNetworks
|
||||
func GetLocalScopeDefaultNetworks() []*net.IPNet {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
return PredefinedLocalScopeDefaultNetworks
|
||||
}
|
||||
|
||||
// ConfigGlobalScopeDefaultNetworks configures global default pool.
|
||||
// Ideally this will be called from SwarmKit as part of swarm init
|
||||
func ConfigGlobalScopeDefaultNetworks(defaultAddressPool []*NetworkToSplit) error {
|
||||
if defaultAddressPool == nil {
|
||||
defaultAddressPool = globalScopeDefaultNetworks
|
||||
}
|
||||
return configDefaultNetworks(defaultAddressPool, &PredefinedGlobalScopeDefaultNetworks)
|
||||
}
|
||||
|
||||
// ConfigLocalScopeDefaultNetworks configures local default pool.
|
||||
// Ideally this will be called during libnetwork init
|
||||
func ConfigLocalScopeDefaultNetworks(defaultAddressPool []*NetworkToSplit) error {
|
||||
if defaultAddressPool == nil {
|
||||
return nil
|
||||
}
|
||||
return configDefaultNetworks(defaultAddressPool, &PredefinedLocalScopeDefaultNetworks)
|
||||
}
|
||||
|
||||
// splitNetworks takes a slice of networks, split them accordingly and returns them
|
||||
func splitNetworks(list []*NetworkToSplit) ([]*net.IPNet, error) {
|
||||
localPools := make([]*net.IPNet, 0, len(list))
|
||||
|
||||
for _, p := range list {
|
||||
_, b, err := net.ParseCIDR(p.Base)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid base pool %q: %v", p.Base, err)
|
||||
}
|
||||
ones, _ := b.Mask.Size()
|
||||
if p.Size <= 0 || p.Size < ones {
|
||||
return nil, fmt.Errorf("invalid pools size: %d", p.Size)
|
||||
}
|
||||
localPools = append(localPools, splitNetwork(p.Size, b)...)
|
||||
}
|
||||
return localPools, nil
|
||||
}
|
||||
|
||||
func splitNetwork(size int, base *net.IPNet) []*net.IPNet {
|
||||
one, bits := base.Mask.Size()
|
||||
mask := net.CIDRMask(size, bits)
|
||||
n := 1 << uint(size-one)
|
||||
s := uint(bits - size)
|
||||
list := make([]*net.IPNet, 0, n)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
ip := copyIP(base.IP)
|
||||
addIntToIP(ip, uint(i<<s))
|
||||
list = append(list, &net.IPNet{IP: ip, Mask: mask})
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func copyIP(from net.IP) net.IP {
|
||||
ip := make([]byte, len(from))
|
||||
copy(ip, from)
|
||||
return ip
|
||||
}
|
||||
|
||||
func addIntToIP(array net.IP, ordinal uint) {
|
||||
for i := len(array) - 1; i >= 0; i-- {
|
||||
array[i] |= (byte)(ordinal & 0xff)
|
||||
ordinal >>= 8
|
||||
}
|
||||
}
|
11
vendor/github.com/docker/libnetwork/netutils/utils.go
generated
vendored
11
vendor/github.com/docker/libnetwork/netutils/utils.go
generated
vendored
@ -14,13 +14,6 @@ import (
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
// constants for the IP address type
|
||||
const (
|
||||
IP = iota // IPv4 and IPv6
|
||||
IPv4
|
||||
IPv6
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNetworkOverlapsWithNameservers preformatted error
|
||||
ErrNetworkOverlapsWithNameservers = errors.New("requested network overlaps with nameserver")
|
||||
@ -177,10 +170,10 @@ func ReverseIP(IP string) string {
|
||||
return strings.Join(reverseIP, ".")
|
||||
}
|
||||
|
||||
// ParseAlias parses and validates the specified string as a alias format (name:alias)
|
||||
// ParseAlias parses and validates the specified string as an alias format (name:alias)
|
||||
func ParseAlias(val string) (string, string, error) {
|
||||
if val == "" {
|
||||
return "", "", fmt.Errorf("empty string specified for alias")
|
||||
return "", "", errors.New("empty string specified for alias")
|
||||
}
|
||||
arr := strings.Split(val, ":")
|
||||
if len(arr) > 2 {
|
||||
|
23
vendor/github.com/docker/libnetwork/netutils/utils_freebsd.go
generated
vendored
Normal file
23
vendor/github.com/docker/libnetwork/netutils/utils_freebsd.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
package netutils
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
// ElectInterfaceAddresses looks for an interface on the OS with the specified name
|
||||
// and returns returns all its IPv4 and IPv6 addresses in CIDR notation.
|
||||
// If a failure in retrieving the addresses or no IPv4 address is found, an error is returned.
|
||||
// If the interface does not exist, it chooses from a predefined
|
||||
// list the first IPv4 address which does not conflict with other
|
||||
// interfaces on the system.
|
||||
func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) {
|
||||
return nil, nil, types.NotImplementedErrorf("not supported on freebsd")
|
||||
}
|
||||
|
||||
// FindAvailableNetwork returns a network from the passed list which does not
|
||||
// overlap with existing interfaces in the system
|
||||
func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {
|
||||
return nil, types.NotImplementedErrorf("not supported on freebsd")
|
||||
}
|
84
vendor/github.com/docker/libnetwork/netutils/utils_linux.go
generated
vendored
84
vendor/github.com/docker/libnetwork/netutils/utils_linux.go
generated
vendored
@ -4,24 +4,31 @@
|
||||
package netutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/libnetwork/ipamutils"
|
||||
"github.com/docker/libnetwork/ns"
|
||||
"github.com/docker/libnetwork/osl"
|
||||
"github.com/docker/libnetwork/resolvconf"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
var (
|
||||
networkGetRoutesFct = netlink.RouteList
|
||||
networkGetRoutesFct func(netlink.Link, int) ([]netlink.Route, error)
|
||||
)
|
||||
|
||||
// CheckRouteOverlaps checks whether the passed network overlaps with any existing routes
|
||||
func CheckRouteOverlaps(toCheck *net.IPNet) error {
|
||||
if networkGetRoutesFct == nil {
|
||||
networkGetRoutesFct = ns.NlHandle().RouteList
|
||||
}
|
||||
networks, err := networkGetRoutesFct(nil, netlink.FAMILY_V4)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, network := range networks {
|
||||
if network.Dst != nil && NetworkOverlaps(toCheck, network.Dst) {
|
||||
return ErrNetworkOverlaps
|
||||
@ -33,13 +40,18 @@ func CheckRouteOverlaps(toCheck *net.IPNet) error {
|
||||
// GenerateIfaceName returns an interface name using the passed in
|
||||
// prefix and the length of random bytes. The api ensures that the
|
||||
// there are is no interface which exists with that name.
|
||||
func GenerateIfaceName(prefix string, len int) (string, error) {
|
||||
func GenerateIfaceName(nlh *netlink.Handle, prefix string, len int) (string, error) {
|
||||
linkByName := netlink.LinkByName
|
||||
if nlh != nil {
|
||||
linkByName = nlh.LinkByName
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
name, err := GenerateRandomName(prefix, len)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if _, err := netlink.LinkByName(name); err != nil {
|
||||
_, err = linkByName(name)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
return name, nil
|
||||
}
|
||||
@ -48,3 +60,67 @@ func GenerateIfaceName(prefix string, len int) (string, error) {
|
||||
}
|
||||
return "", types.InternalErrorf("could not generate interface name")
|
||||
}
|
||||
|
||||
// ElectInterfaceAddresses looks for an interface on the OS with the
|
||||
// specified name and returns returns all its IPv4 and IPv6 addresses in CIDR notation.
|
||||
// If a failure in retrieving the addresses or no IPv4 address is found, an error is returned.
|
||||
// If the interface does not exist, it chooses from a predefined
|
||||
// list the first IPv4 address which does not conflict with other
|
||||
// interfaces on the system.
|
||||
func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) {
|
||||
var (
|
||||
v4Nets []*net.IPNet
|
||||
v6Nets []*net.IPNet
|
||||
)
|
||||
|
||||
defer osl.InitOSContext()()
|
||||
|
||||
link, _ := ns.NlHandle().LinkByName(name)
|
||||
if link != nil {
|
||||
v4addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V4)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
v6addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V6)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, nlAddr := range v4addr {
|
||||
v4Nets = append(v4Nets, nlAddr.IPNet)
|
||||
}
|
||||
for _, nlAddr := range v6addr {
|
||||
v6Nets = append(v6Nets, nlAddr.IPNet)
|
||||
}
|
||||
}
|
||||
|
||||
if link == nil || len(v4Nets) == 0 {
|
||||
// Choose from predefined local scope networks
|
||||
v4Net, err := FindAvailableNetwork(ipamutils.PredefinedLocalScopeDefaultNetworks)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
v4Nets = append(v4Nets, v4Net)
|
||||
}
|
||||
|
||||
return v4Nets, v6Nets, nil
|
||||
}
|
||||
|
||||
// FindAvailableNetwork returns a network from the passed list which does not
|
||||
// overlap with existing interfaces in the system
|
||||
func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {
|
||||
// We don't check for an error here, because we don't really care if we
|
||||
// can't read /etc/resolv.conf. So instead we skip the append if resolvConf
|
||||
// is nil. It either doesn't exist, or we can't read it for some reason.
|
||||
var nameservers []string
|
||||
if rc, err := resolvconf.Get(); err == nil {
|
||||
nameservers = resolvconf.GetNameserversAsCIDR(rc.Content)
|
||||
}
|
||||
for _, nw := range list {
|
||||
if err := CheckNameserverOverlaps(nameservers, nw); err == nil {
|
||||
if err := CheckRouteOverlaps(nw); err == nil {
|
||||
return nw, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("no available network")
|
||||
}
|
||||
|
25
vendor/github.com/docker/libnetwork/netutils/utils_windows.go
generated
vendored
Normal file
25
vendor/github.com/docker/libnetwork/netutils/utils_windows.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
package netutils
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
// ElectInterfaceAddresses looks for an interface on the OS with the specified name
|
||||
// and returns returns all its IPv4 and IPv6 addresses in CIDR notation.
|
||||
// If a failure in retrieving the addresses or no IPv4 address is found, an error is returned.
|
||||
// If the interface does not exist, it chooses from a predefined
|
||||
// list the first IPv4 address which does not conflict with other
|
||||
// interfaces on the system.
|
||||
func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) {
|
||||
return nil, nil, types.NotImplementedErrorf("not supported on windows")
|
||||
}
|
||||
|
||||
// FindAvailableNetwork returns a network from the passed list which does not
|
||||
// overlap with existing interfaces in the system
|
||||
|
||||
// TODO : Use appropriate windows APIs to identify non-overlapping subnets
|
||||
func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {
|
||||
return nil, nil
|
||||
}
|
140
vendor/github.com/docker/libnetwork/ns/init_linux.go
generated
vendored
Normal file
140
vendor/github.com/docker/libnetwork/ns/init_linux.go
generated
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
package ns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/vishvananda/netlink"
|
||||
"github.com/vishvananda/netns"
|
||||
)
|
||||
|
||||
var (
|
||||
initNs netns.NsHandle
|
||||
initNl *netlink.Handle
|
||||
initOnce sync.Once
|
||||
// NetlinkSocketsTimeout represents the default timeout duration for the sockets
|
||||
NetlinkSocketsTimeout = 3 * time.Second
|
||||
)
|
||||
|
||||
// Init initializes a new network namespace
|
||||
func Init() {
|
||||
var err error
|
||||
initNs, err = netns.Get()
|
||||
if err != nil {
|
||||
logrus.Errorf("could not get initial namespace: %v", err)
|
||||
}
|
||||
initNl, err = netlink.NewHandle(getSupportedNlFamilies()...)
|
||||
if err != nil {
|
||||
logrus.Errorf("could not create netlink handle on initial namespace: %v", err)
|
||||
}
|
||||
err = initNl.SetSocketTimeout(NetlinkSocketsTimeout)
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed to set the timeout on the default netlink handle sockets: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// SetNamespace sets the initial namespace handler
|
||||
func SetNamespace() error {
|
||||
initOnce.Do(Init)
|
||||
if err := netns.Set(initNs); err != nil {
|
||||
linkInfo, linkErr := getLink()
|
||||
if linkErr != nil {
|
||||
linkInfo = linkErr.Error()
|
||||
}
|
||||
return fmt.Errorf("failed to set to initial namespace, %v, initns fd %d: %v", linkInfo, initNs, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseHandlerInt transforms the namespace handler into an integer
|
||||
func ParseHandlerInt() int {
|
||||
return int(getHandler())
|
||||
}
|
||||
|
||||
// GetHandler returns the namespace handler
|
||||
func getHandler() netns.NsHandle {
|
||||
initOnce.Do(Init)
|
||||
return initNs
|
||||
}
|
||||
|
||||
func getLink() (string, error) {
|
||||
return os.Readlink(fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid()))
|
||||
}
|
||||
|
||||
// NlHandle returns the netlink handler
|
||||
func NlHandle() *netlink.Handle {
|
||||
initOnce.Do(Init)
|
||||
return initNl
|
||||
}
|
||||
|
||||
func getSupportedNlFamilies() []int {
|
||||
fams := []int{syscall.NETLINK_ROUTE}
|
||||
// NETLINK_XFRM test
|
||||
if err := loadXfrmModules(); err != nil {
|
||||
if checkXfrmSocket() != nil {
|
||||
logrus.Warnf("Could not load necessary modules for IPSEC rules: %v", err)
|
||||
} else {
|
||||
fams = append(fams, syscall.NETLINK_XFRM)
|
||||
}
|
||||
} else {
|
||||
fams = append(fams, syscall.NETLINK_XFRM)
|
||||
}
|
||||
// NETLINK_NETFILTER test
|
||||
if err := loadNfConntrackModules(); err != nil {
|
||||
if checkNfSocket() != nil {
|
||||
logrus.Warnf("Could not load necessary modules for Conntrack: %v", err)
|
||||
} else {
|
||||
fams = append(fams, syscall.NETLINK_NETFILTER)
|
||||
}
|
||||
} else {
|
||||
fams = append(fams, syscall.NETLINK_NETFILTER)
|
||||
}
|
||||
|
||||
return fams
|
||||
}
|
||||
|
||||
func loadXfrmModules() error {
|
||||
if out, err := exec.Command("modprobe", "-va", "xfrm_user").CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("Running modprobe xfrm_user failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
|
||||
}
|
||||
if out, err := exec.Command("modprobe", "-va", "xfrm_algo").CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("Running modprobe xfrm_algo failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// API check on required xfrm modules (xfrm_user, xfrm_algo)
|
||||
func checkXfrmSocket() error {
|
||||
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_XFRM)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
syscall.Close(fd)
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadNfConntrackModules() error {
|
||||
if out, err := exec.Command("modprobe", "-va", "nf_conntrack").CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("Running modprobe nf_conntrack failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
|
||||
}
|
||||
if out, err := exec.Command("modprobe", "-va", "nf_conntrack_netlink").CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("Running modprobe nf_conntrack_netlink failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// API check on required nf_conntrack* modules (nf_conntrack, nf_conntrack_netlink)
|
||||
func checkNfSocket() error {
|
||||
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_NETFILTER)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
syscall.Close(fd)
|
||||
return nil
|
||||
}
|
3
vendor/github.com/docker/libnetwork/ns/init_windows.go
generated
vendored
Normal file
3
vendor/github.com/docker/libnetwork/ns/init_windows.go
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package ns
|
||||
|
||||
// File is present so that go build ./... is closer to working on Windows from repo root.
|
4
vendor/github.com/docker/libnetwork/osl/interface_freebsd.go
generated
vendored
Normal file
4
vendor/github.com/docker/libnetwork/osl/interface_freebsd.go
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
package osl
|
||||
|
||||
// IfaceOption is a function option type to set interface options
|
||||
type IfaceOption func()
|
460
vendor/github.com/docker/libnetwork/osl/interface_linux.go
generated
vendored
Normal file
460
vendor/github.com/docker/libnetwork/osl/interface_linux.go
generated
vendored
Normal file
@ -0,0 +1,460 @@
|
||||
package osl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/docker/libnetwork/ns"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/vishvananda/netlink"
|
||||
"github.com/vishvananda/netns"
|
||||
)
|
||||
|
||||
// IfaceOption is a function option type to set interface options
|
||||
type IfaceOption func(i *nwIface)
|
||||
|
||||
type nwIface struct {
|
||||
srcName string
|
||||
dstName string
|
||||
master string
|
||||
dstMaster string
|
||||
mac net.HardwareAddr
|
||||
address *net.IPNet
|
||||
addressIPv6 *net.IPNet
|
||||
llAddrs []*net.IPNet
|
||||
routes []*net.IPNet
|
||||
bridge bool
|
||||
ns *networkNamespace
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func (i *nwIface) SrcName() string {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
|
||||
return i.srcName
|
||||
}
|
||||
|
||||
func (i *nwIface) DstName() string {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
|
||||
return i.dstName
|
||||
}
|
||||
|
||||
func (i *nwIface) DstMaster() string {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
|
||||
return i.dstMaster
|
||||
}
|
||||
|
||||
func (i *nwIface) Bridge() bool {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
|
||||
return i.bridge
|
||||
}
|
||||
|
||||
func (i *nwIface) Master() string {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
|
||||
return i.master
|
||||
}
|
||||
|
||||
func (i *nwIface) MacAddress() net.HardwareAddr {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
|
||||
return types.GetMacCopy(i.mac)
|
||||
}
|
||||
|
||||
func (i *nwIface) Address() *net.IPNet {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
|
||||
return types.GetIPNetCopy(i.address)
|
||||
}
|
||||
|
||||
func (i *nwIface) AddressIPv6() *net.IPNet {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
|
||||
return types.GetIPNetCopy(i.addressIPv6)
|
||||
}
|
||||
|
||||
func (i *nwIface) LinkLocalAddresses() []*net.IPNet {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
|
||||
return i.llAddrs
|
||||
}
|
||||
|
||||
func (i *nwIface) Routes() []*net.IPNet {
|
||||
i.Lock()
|
||||
defer i.Unlock()
|
||||
|
||||
routes := make([]*net.IPNet, len(i.routes))
|
||||
for index, route := range i.routes {
|
||||
r := types.GetIPNetCopy(route)
|
||||
routes[index] = r
|
||||
}
|
||||
|
||||
return routes
|
||||
}
|
||||
|
||||
func (n *networkNamespace) Interfaces() []Interface {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
ifaces := make([]Interface, len(n.iFaces))
|
||||
|
||||
for i, iface := range n.iFaces {
|
||||
ifaces[i] = iface
|
||||
}
|
||||
|
||||
return ifaces
|
||||
}
|
||||
|
||||
func (i *nwIface) Remove() error {
|
||||
i.Lock()
|
||||
n := i.ns
|
||||
i.Unlock()
|
||||
|
||||
n.Lock()
|
||||
isDefault := n.isDefault
|
||||
nlh := n.nlHandle
|
||||
n.Unlock()
|
||||
|
||||
// Find the network interface identified by the DstName attribute.
|
||||
iface, err := nlh.LinkByName(i.DstName())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Down the interface before configuring
|
||||
if err := nlh.LinkSetDown(iface); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = nlh.LinkSetName(iface, i.SrcName())
|
||||
if err != nil {
|
||||
logrus.Debugf("LinkSetName failed for interface %s: %v", i.SrcName(), err)
|
||||
return err
|
||||
}
|
||||
|
||||
// if it is a bridge just delete it.
|
||||
if i.Bridge() {
|
||||
if err := nlh.LinkDel(iface); err != nil {
|
||||
return fmt.Errorf("failed deleting bridge %q: %v", i.SrcName(), err)
|
||||
}
|
||||
} else if !isDefault {
|
||||
// Move the network interface to caller namespace.
|
||||
if err := nlh.LinkSetNsFd(iface, ns.ParseHandlerInt()); err != nil {
|
||||
logrus.Debugf("LinkSetNsPid failed for interface %s: %v", i.SrcName(), err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
n.Lock()
|
||||
for index, intf := range n.iFaces {
|
||||
if intf == i {
|
||||
n.iFaces = append(n.iFaces[:index], n.iFaces[index+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
n.Unlock()
|
||||
|
||||
n.checkLoV6()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the sandbox's side veth interface statistics
|
||||
func (i *nwIface) Statistics() (*types.InterfaceStatistics, error) {
|
||||
i.Lock()
|
||||
n := i.ns
|
||||
i.Unlock()
|
||||
|
||||
l, err := n.nlHandle.LinkByName(i.DstName())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve the statistics for %s in netns %s: %v", i.DstName(), n.path, err)
|
||||
}
|
||||
|
||||
stats := l.Attrs().Statistics
|
||||
if stats == nil {
|
||||
return nil, fmt.Errorf("no statistics were returned")
|
||||
}
|
||||
|
||||
return &types.InterfaceStatistics{
|
||||
RxBytes: uint64(stats.RxBytes),
|
||||
TxBytes: uint64(stats.TxBytes),
|
||||
RxPackets: uint64(stats.RxPackets),
|
||||
TxPackets: uint64(stats.TxPackets),
|
||||
RxDropped: uint64(stats.RxDropped),
|
||||
TxDropped: uint64(stats.TxDropped),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (n *networkNamespace) findDst(srcName string, isBridge bool) string {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
for _, i := range n.iFaces {
|
||||
// The master should match the srcname of the interface and the
|
||||
// master interface should be of type bridge, if searching for a bridge type
|
||||
if i.SrcName() == srcName && (!isBridge || i.Bridge()) {
|
||||
return i.DstName()
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...IfaceOption) error {
|
||||
i := &nwIface{srcName: srcName, dstName: dstPrefix, ns: n}
|
||||
i.processInterfaceOptions(options...)
|
||||
|
||||
if i.master != "" {
|
||||
i.dstMaster = n.findDst(i.master, true)
|
||||
if i.dstMaster == "" {
|
||||
return fmt.Errorf("could not find an appropriate master %q for %q",
|
||||
i.master, i.srcName)
|
||||
}
|
||||
}
|
||||
|
||||
n.Lock()
|
||||
if n.isDefault {
|
||||
i.dstName = i.srcName
|
||||
} else {
|
||||
i.dstName = fmt.Sprintf("%s%d", dstPrefix, n.nextIfIndex[dstPrefix])
|
||||
n.nextIfIndex[dstPrefix]++
|
||||
}
|
||||
|
||||
path := n.path
|
||||
isDefault := n.isDefault
|
||||
nlh := n.nlHandle
|
||||
nlhHost := ns.NlHandle()
|
||||
n.Unlock()
|
||||
|
||||
// If it is a bridge interface we have to create the bridge inside
|
||||
// the namespace so don't try to lookup the interface using srcName
|
||||
if i.bridge {
|
||||
link := &netlink.Bridge{
|
||||
LinkAttrs: netlink.LinkAttrs{
|
||||
Name: i.srcName,
|
||||
},
|
||||
}
|
||||
if err := nlh.LinkAdd(link); err != nil {
|
||||
return fmt.Errorf("failed to create bridge %q: %v", i.srcName, err)
|
||||
}
|
||||
} else {
|
||||
// Find the network interface identified by the SrcName attribute.
|
||||
iface, err := nlhHost.LinkByName(i.srcName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
|
||||
}
|
||||
|
||||
// Move the network interface to the destination
|
||||
// namespace only if the namespace is not a default
|
||||
// type
|
||||
if !isDefault {
|
||||
newNs, err := netns.GetFromPath(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed get network namespace %q: %v", path, err)
|
||||
}
|
||||
defer newNs.Close()
|
||||
if err := nlhHost.LinkSetNsFd(iface, int(newNs)); err != nil {
|
||||
return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the network interface identified by the SrcName attribute.
|
||||
iface, err := nlh.LinkByName(i.srcName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
|
||||
}
|
||||
|
||||
// Down the interface before configuring
|
||||
if err := nlh.LinkSetDown(iface); err != nil {
|
||||
return fmt.Errorf("failed to set link down: %v", err)
|
||||
}
|
||||
|
||||
// Configure the interface now this is moved in the proper namespace.
|
||||
if err := configureInterface(nlh, iface, i); err != nil {
|
||||
// If configuring the device fails move it back to the host namespace
|
||||
// and change the name back to the source name. This allows the caller
|
||||
// to properly cleanup the interface. Its important especially for
|
||||
// interfaces with global attributes, ex: vni id for vxlan interfaces.
|
||||
if nerr := nlh.LinkSetName(iface, i.SrcName()); nerr != nil {
|
||||
logrus.Errorf("renaming interface (%s->%s) failed, %v after config error %v", i.DstName(), i.SrcName(), nerr, err)
|
||||
}
|
||||
if nerr := nlh.LinkSetNsFd(iface, ns.ParseHandlerInt()); nerr != nil {
|
||||
logrus.Errorf("moving interface %s to host ns failed, %v, after config error %v", i.SrcName(), nerr, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Up the interface.
|
||||
cnt := 0
|
||||
for err = nlh.LinkSetUp(iface); err != nil && cnt < 3; cnt++ {
|
||||
logrus.Debugf("retrying link setup because of: %v", err)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
err = nlh.LinkSetUp(iface)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set link up: %v", err)
|
||||
}
|
||||
|
||||
// Set the routes on the interface. This can only be done when the interface is up.
|
||||
if err := setInterfaceRoutes(nlh, iface, i); err != nil {
|
||||
return fmt.Errorf("error setting interface %q routes to %q: %v", iface.Attrs().Name, i.Routes(), err)
|
||||
}
|
||||
|
||||
n.Lock()
|
||||
n.iFaces = append(n.iFaces, i)
|
||||
n.Unlock()
|
||||
|
||||
n.checkLoV6()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func configureInterface(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
|
||||
ifaceName := iface.Attrs().Name
|
||||
ifaceConfigurators := []struct {
|
||||
Fn func(*netlink.Handle, netlink.Link, *nwIface) error
|
||||
ErrMessage string
|
||||
}{
|
||||
{setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, i.DstName())},
|
||||
{setInterfaceMAC, fmt.Sprintf("error setting interface %q MAC to %q", ifaceName, i.MacAddress())},
|
||||
{setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %v", ifaceName, i.Address())},
|
||||
{setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %v", ifaceName, i.AddressIPv6())},
|
||||
{setInterfaceMaster, fmt.Sprintf("error setting interface %q master to %q", ifaceName, i.DstMaster())},
|
||||
{setInterfaceLinkLocalIPs, fmt.Sprintf("error setting interface %q link local IPs to %v", ifaceName, i.LinkLocalAddresses())},
|
||||
}
|
||||
|
||||
for _, config := range ifaceConfigurators {
|
||||
if err := config.Fn(nlh, iface, i); err != nil {
|
||||
return fmt.Errorf("%s: %v", config.ErrMessage, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setInterfaceMaster(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
|
||||
if i.DstMaster() == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nlh.LinkSetMaster(iface, &netlink.Bridge{
|
||||
LinkAttrs: netlink.LinkAttrs{Name: i.DstMaster()}})
|
||||
}
|
||||
|
||||
func setInterfaceMAC(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
|
||||
if i.MacAddress() == nil {
|
||||
return nil
|
||||
}
|
||||
return nlh.LinkSetHardwareAddr(iface, i.MacAddress())
|
||||
}
|
||||
|
||||
func setInterfaceIP(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
|
||||
if i.Address() == nil {
|
||||
return nil
|
||||
}
|
||||
if err := checkRouteConflict(nlh, i.Address(), netlink.FAMILY_V4); err != nil {
|
||||
return err
|
||||
}
|
||||
ipAddr := &netlink.Addr{IPNet: i.Address(), Label: ""}
|
||||
return nlh.AddrAdd(iface, ipAddr)
|
||||
}
|
||||
|
||||
func setInterfaceIPv6(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
|
||||
if i.AddressIPv6() == nil {
|
||||
return nil
|
||||
}
|
||||
if err := checkRouteConflict(nlh, i.AddressIPv6(), netlink.FAMILY_V6); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setIPv6(i.ns.path, i.DstName(), true); err != nil {
|
||||
return fmt.Errorf("failed to enable ipv6: %v", err)
|
||||
}
|
||||
ipAddr := &netlink.Addr{IPNet: i.AddressIPv6(), Label: "", Flags: syscall.IFA_F_NODAD}
|
||||
return nlh.AddrAdd(iface, ipAddr)
|
||||
}
|
||||
|
||||
func setInterfaceLinkLocalIPs(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
|
||||
for _, llIP := range i.LinkLocalAddresses() {
|
||||
ipAddr := &netlink.Addr{IPNet: llIP}
|
||||
if err := nlh.AddrAdd(iface, ipAddr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setInterfaceName(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
|
||||
return nlh.LinkSetName(iface, i.DstName())
|
||||
}
|
||||
|
||||
func setInterfaceRoutes(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
|
||||
for _, route := range i.Routes() {
|
||||
err := nlh.RouteAdd(&netlink.Route{
|
||||
Scope: netlink.SCOPE_LINK,
|
||||
LinkIndex: iface.Attrs().Index,
|
||||
Dst: route,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// In older kernels (like the one in Centos 6.6 distro) sysctl does not have netns support. Therefore
|
||||
// we cannot gather the statistics from /sys/class/net/<dev>/statistics/<counter> files. Per-netns stats
|
||||
// are naturally found in /proc/net/dev in kernels which support netns (ifconfig relies on that).
|
||||
const (
|
||||
netStatsFile = "/proc/net/dev"
|
||||
base = "[ ]*%s:([ ]+[0-9]+){16}"
|
||||
)
|
||||
|
||||
func scanInterfaceStats(data, ifName string, i *types.InterfaceStatistics) error {
|
||||
var (
|
||||
bktStr string
|
||||
bkt uint64
|
||||
)
|
||||
|
||||
regex := fmt.Sprintf(base, ifName)
|
||||
re := regexp.MustCompile(regex)
|
||||
line := re.FindString(data)
|
||||
|
||||
_, err := fmt.Sscanf(line, "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
|
||||
&bktStr, &i.RxBytes, &i.RxPackets, &i.RxErrors, &i.RxDropped, &bkt, &bkt, &bkt,
|
||||
&bkt, &i.TxBytes, &i.TxPackets, &i.TxErrors, &i.TxDropped, &bkt, &bkt, &bkt, &bkt)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func checkRouteConflict(nlh *netlink.Handle, address *net.IPNet, family int) error {
|
||||
routes, err := nlh.RouteList(nil, family)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, route := range routes {
|
||||
if route.Dst != nil {
|
||||
if route.Dst.Contains(address.IP) || address.Contains(route.Dst.IP) {
|
||||
return fmt.Errorf("cannot program address %v in sandbox interface because it conflicts with existing route %s",
|
||||
address, route)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
4
vendor/github.com/docker/libnetwork/osl/interface_windows.go
generated
vendored
Normal file
4
vendor/github.com/docker/libnetwork/osl/interface_windows.go
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
package osl
|
||||
|
||||
// IfaceOption is a function option type to set interface options
|
||||
type IfaceOption func()
|
16
vendor/github.com/docker/libnetwork/osl/kernel/knobs.go
generated
vendored
Normal file
16
vendor/github.com/docker/libnetwork/osl/kernel/knobs.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
package kernel
|
||||
|
||||
type conditionalCheck func(val1, val2 string) bool
|
||||
|
||||
// OSValue represents a tuple, value defined, check function when to apply the value
|
||||
type OSValue struct {
|
||||
Value string
|
||||
CheckFn conditionalCheck
|
||||
}
|
||||
|
||||
func propertyIsValid(val1, val2 string, check conditionalCheck) bool {
|
||||
if check == nil || check(val1, val2) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
47
vendor/github.com/docker/libnetwork/osl/kernel/knobs_linux.go
generated
vendored
Normal file
47
vendor/github.com/docker/libnetwork/osl/kernel/knobs_linux.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
package kernel
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// writeSystemProperty writes the value to a path under /proc/sys as determined from the key.
|
||||
// For e.g. net.ipv4.ip_forward translated to /proc/sys/net/ipv4/ip_forward.
|
||||
func writeSystemProperty(key, value string) error {
|
||||
keyPath := strings.Replace(key, ".", "/", -1)
|
||||
return ioutil.WriteFile(path.Join("/proc/sys", keyPath), []byte(value), 0644)
|
||||
}
|
||||
|
||||
// readSystemProperty reads the value from the path under /proc/sys and returns it
|
||||
func readSystemProperty(key string) (string, error) {
|
||||
keyPath := strings.Replace(key, ".", "/", -1)
|
||||
value, err := ioutil.ReadFile(path.Join("/proc/sys", keyPath))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(string(value)), nil
|
||||
}
|
||||
|
||||
// ApplyOSTweaks applies the configuration values passed as arguments
|
||||
func ApplyOSTweaks(osConfig map[string]*OSValue) {
|
||||
for k, v := range osConfig {
|
||||
// read the existing property from disk
|
||||
oldv, err := readSystemProperty(k)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Errorf("error reading the kernel parameter %s", k)
|
||||
continue
|
||||
}
|
||||
|
||||
if propertyIsValid(oldv, v.Value, v.CheckFn) {
|
||||
// write new prop value to disk
|
||||
if err := writeSystemProperty(k, v.Value); err != nil {
|
||||
logrus.WithError(err).Errorf("error setting the kernel parameter %s = %s, (leaving as %s)", k, v.Value, oldv)
|
||||
continue
|
||||
}
|
||||
logrus.Debugf("updated kernel parameter %s = %s (was %s)", k, v.Value, oldv)
|
||||
}
|
||||
}
|
||||
}
|
7
vendor/github.com/docker/libnetwork/osl/kernel/knobs_unsupported.go
generated
vendored
Normal file
7
vendor/github.com/docker/libnetwork/osl/kernel/knobs_unsupported.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// +build !linux
|
||||
|
||||
package kernel
|
||||
|
||||
// ApplyOSTweaks applies the configuration values passed as arguments
|
||||
func ApplyOSTweaks(osConfig map[string]*OSValue) {
|
||||
}
|
657
vendor/github.com/docker/libnetwork/osl/namespace_linux.go
generated
vendored
Normal file
657
vendor/github.com/docker/libnetwork/osl/namespace_linux.go
generated
vendored
Normal file
@ -0,0 +1,657 @@
|
||||
package osl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/docker/libnetwork/ns"
|
||||
"github.com/docker/libnetwork/osl/kernel"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/vishvananda/netlink"
|
||||
"github.com/vishvananda/netns"
|
||||
)
|
||||
|
||||
const defaultPrefix = "/var/run/docker"
|
||||
|
||||
func init() {
|
||||
reexec.Register("set-ipv6", reexecSetIPv6)
|
||||
}
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
garbagePathMap = make(map[string]bool)
|
||||
gpmLock sync.Mutex
|
||||
gpmWg sync.WaitGroup
|
||||
gpmCleanupPeriod = 60 * time.Second
|
||||
gpmChan = make(chan chan struct{})
|
||||
prefix = defaultPrefix
|
||||
loadBalancerConfig = map[string]*kernel.OSValue{
|
||||
// expires connection from the IPVS connection table when the backend is not available
|
||||
// more info: https://github.com/torvalds/linux/blob/master/Documentation/networking/ipvs-sysctl.txt#L126:1
|
||||
"net.ipv4.vs.expire_nodest_conn": {"1", nil},
|
||||
}
|
||||
)
|
||||
|
||||
// The networkNamespace type is the linux implementation of the Sandbox
|
||||
// interface. It represents a linux network namespace, and moves an interface
|
||||
// into it when called on method AddInterface or sets the gateway etc.
|
||||
type networkNamespace struct {
|
||||
path string
|
||||
iFaces []*nwIface
|
||||
gw net.IP
|
||||
gwv6 net.IP
|
||||
staticRoutes []*types.StaticRoute
|
||||
neighbors []*neigh
|
||||
nextIfIndex map[string]int
|
||||
isDefault bool
|
||||
nlHandle *netlink.Handle
|
||||
loV6Enabled bool
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
// SetBasePath sets the base url prefix for the ns path
|
||||
func SetBasePath(path string) {
|
||||
prefix = path
|
||||
}
|
||||
|
||||
func init() {
|
||||
reexec.Register("netns-create", reexecCreateNamespace)
|
||||
}
|
||||
|
||||
func basePath() string {
|
||||
return filepath.Join(prefix, "netns")
|
||||
}
|
||||
|
||||
func createBasePath() {
|
||||
err := os.MkdirAll(basePath(), 0755)
|
||||
if err != nil {
|
||||
panic("Could not create net namespace path directory")
|
||||
}
|
||||
|
||||
// Start the garbage collection go routine
|
||||
go removeUnusedPaths()
|
||||
}
|
||||
|
||||
func removeUnusedPaths() {
|
||||
gpmLock.Lock()
|
||||
period := gpmCleanupPeriod
|
||||
gpmLock.Unlock()
|
||||
|
||||
ticker := time.NewTicker(period)
|
||||
for {
|
||||
var (
|
||||
gc chan struct{}
|
||||
gcOk bool
|
||||
)
|
||||
|
||||
select {
|
||||
case <-ticker.C:
|
||||
case gc, gcOk = <-gpmChan:
|
||||
}
|
||||
|
||||
gpmLock.Lock()
|
||||
pathList := make([]string, 0, len(garbagePathMap))
|
||||
for path := range garbagePathMap {
|
||||
pathList = append(pathList, path)
|
||||
}
|
||||
garbagePathMap = make(map[string]bool)
|
||||
gpmWg.Add(1)
|
||||
gpmLock.Unlock()
|
||||
|
||||
for _, path := range pathList {
|
||||
os.Remove(path)
|
||||
}
|
||||
|
||||
gpmWg.Done()
|
||||
if gcOk {
|
||||
close(gc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addToGarbagePaths(path string) {
|
||||
gpmLock.Lock()
|
||||
garbagePathMap[path] = true
|
||||
gpmLock.Unlock()
|
||||
}
|
||||
|
||||
func removeFromGarbagePaths(path string) {
|
||||
gpmLock.Lock()
|
||||
delete(garbagePathMap, path)
|
||||
gpmLock.Unlock()
|
||||
}
|
||||
|
||||
// GC triggers garbage collection of namespace path right away
|
||||
// and waits for it.
|
||||
func GC() {
|
||||
gpmLock.Lock()
|
||||
if len(garbagePathMap) == 0 {
|
||||
// No need for GC if map is empty
|
||||
gpmLock.Unlock()
|
||||
return
|
||||
}
|
||||
gpmLock.Unlock()
|
||||
|
||||
// if content exists in the garbage paths
|
||||
// we can trigger GC to run, providing a
|
||||
// channel to be notified on completion
|
||||
waitGC := make(chan struct{})
|
||||
gpmChan <- waitGC
|
||||
// wait for GC completion
|
||||
<-waitGC
|
||||
}
|
||||
|
||||
// GenerateKey generates a sandbox key based on the passed
|
||||
// container id.
|
||||
func GenerateKey(containerID string) string {
|
||||
maxLen := 12
|
||||
// Read sandbox key from host for overlay
|
||||
if strings.HasPrefix(containerID, "-") {
|
||||
var (
|
||||
index int
|
||||
indexStr string
|
||||
tmpkey string
|
||||
)
|
||||
dir, err := ioutil.ReadDir(basePath())
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
for _, v := range dir {
|
||||
id := v.Name()
|
||||
if strings.HasSuffix(id, containerID[:maxLen-1]) {
|
||||
indexStr = strings.TrimSuffix(id, containerID[:maxLen-1])
|
||||
tmpindex, err := strconv.Atoi(indexStr)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if tmpindex > index {
|
||||
index = tmpindex
|
||||
tmpkey = id
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
containerID = tmpkey
|
||||
if containerID == "" {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
if len(containerID) < maxLen {
|
||||
maxLen = len(containerID)
|
||||
}
|
||||
|
||||
return basePath() + "/" + containerID[:maxLen]
|
||||
}
|
||||
|
||||
// NewSandbox provides a new sandbox instance created in an os specific way
|
||||
// provided a key which uniquely identifies the sandbox
|
||||
func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
|
||||
if !isRestore {
|
||||
err := createNetworkNamespace(key, osCreate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
once.Do(createBasePath)
|
||||
}
|
||||
|
||||
n := &networkNamespace{path: key, isDefault: !osCreate, nextIfIndex: make(map[string]int)}
|
||||
|
||||
sboxNs, err := netns.GetFromPath(n.path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed get network namespace %q: %v", n.path, err)
|
||||
}
|
||||
defer sboxNs.Close()
|
||||
|
||||
n.nlHandle, err = netlink.NewHandleAt(sboxNs, syscall.NETLINK_ROUTE)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create a netlink handle: %v", err)
|
||||
}
|
||||
|
||||
err = n.nlHandle.SetSocketTimeout(ns.NetlinkSocketsTimeout)
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed to set the timeout on the sandbox netlink handle sockets: %v", err)
|
||||
}
|
||||
// In live-restore mode, IPV6 entries are getting cleaned up due to below code
|
||||
// We should retain IPV6 configurations in live-restore mode when Docker Daemon
|
||||
// comes back. It should work as it is on other cases
|
||||
// As starting point, disable IPv6 on all interfaces
|
||||
if !isRestore && !n.isDefault {
|
||||
err = setIPv6(n.path, "all", false)
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed to disable IPv6 on all interfaces on network namespace %q: %v", n.path, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = n.loopbackUp(); err != nil {
|
||||
n.nlHandle.Delete()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (n *networkNamespace) InterfaceOptions() IfaceOptionSetter {
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *networkNamespace) NeighborOptions() NeighborOptionSetter {
|
||||
return n
|
||||
}
|
||||
|
||||
func mountNetworkNamespace(basePath string, lnPath string) error {
|
||||
return syscall.Mount(basePath, lnPath, "bind", syscall.MS_BIND, "")
|
||||
}
|
||||
|
||||
// GetSandboxForExternalKey returns sandbox object for the supplied path
|
||||
func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) {
|
||||
if err := createNamespaceFile(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := mountNetworkNamespace(basePath, key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n := &networkNamespace{path: key, nextIfIndex: make(map[string]int)}
|
||||
|
||||
sboxNs, err := netns.GetFromPath(n.path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed get network namespace %q: %v", n.path, err)
|
||||
}
|
||||
defer sboxNs.Close()
|
||||
|
||||
n.nlHandle, err = netlink.NewHandleAt(sboxNs, syscall.NETLINK_ROUTE)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create a netlink handle: %v", err)
|
||||
}
|
||||
|
||||
err = n.nlHandle.SetSocketTimeout(ns.NetlinkSocketsTimeout)
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed to set the timeout on the sandbox netlink handle sockets: %v", err)
|
||||
}
|
||||
|
||||
// As starting point, disable IPv6 on all interfaces
|
||||
err = setIPv6(n.path, "all", false)
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed to disable IPv6 on all interfaces on network namespace %q: %v", n.path, err)
|
||||
}
|
||||
|
||||
if err = n.loopbackUp(); err != nil {
|
||||
n.nlHandle.Delete()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func reexecCreateNamespace() {
|
||||
if len(os.Args) < 2 {
|
||||
logrus.Fatal("no namespace path provided")
|
||||
}
|
||||
if err := mountNetworkNamespace("/proc/self/ns/net", os.Args[1]); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func createNetworkNamespace(path string, osCreate bool) error {
|
||||
if err := createNamespaceFile(path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := &exec.Cmd{
|
||||
Path: reexec.Self(),
|
||||
Args: append([]string{"netns-create"}, path),
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
}
|
||||
if osCreate {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWNET
|
||||
}
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("namespace creation reexec command failed: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmountNamespaceFile(path string) {
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
syscall.Unmount(path, syscall.MNT_DETACH)
|
||||
}
|
||||
}
|
||||
|
||||
func createNamespaceFile(path string) (err error) {
|
||||
var f *os.File
|
||||
|
||||
once.Do(createBasePath)
|
||||
// Remove it from garbage collection list if present
|
||||
removeFromGarbagePaths(path)
|
||||
|
||||
// If the path is there unmount it first
|
||||
unmountNamespaceFile(path)
|
||||
|
||||
// wait for garbage collection to complete if it is in progress
|
||||
// before trying to create the file.
|
||||
gpmWg.Wait()
|
||||
|
||||
if f, err = os.Create(path); err == nil {
|
||||
f.Close()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *networkNamespace) loopbackUp() error {
|
||||
iface, err := n.nlHandle.LinkByName("lo")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return n.nlHandle.LinkSetUp(iface)
|
||||
}
|
||||
|
||||
func (n *networkNamespace) GetLoopbackIfaceName() string {
|
||||
return "lo"
|
||||
}
|
||||
|
||||
func (n *networkNamespace) AddAliasIP(ifName string, ip *net.IPNet) error {
|
||||
iface, err := n.nlHandle.LinkByName(ifName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return n.nlHandle.AddrAdd(iface, &netlink.Addr{IPNet: ip})
|
||||
}
|
||||
|
||||
func (n *networkNamespace) RemoveAliasIP(ifName string, ip *net.IPNet) error {
|
||||
iface, err := n.nlHandle.LinkByName(ifName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return n.nlHandle.AddrDel(iface, &netlink.Addr{IPNet: ip})
|
||||
}
|
||||
|
||||
func (n *networkNamespace) InvokeFunc(f func()) error {
|
||||
return nsInvoke(n.nsPath(), func(nsFD int) error { return nil }, func(callerFD int) error {
|
||||
f()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// InitOSContext initializes OS context while configuring network resources
|
||||
func InitOSContext() func() {
|
||||
runtime.LockOSThread()
|
||||
if err := ns.SetNamespace(); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
return runtime.UnlockOSThread
|
||||
}
|
||||
|
||||
func nsInvoke(path string, prefunc func(nsFD int) error, postfunc func(callerFD int) error) error {
|
||||
defer InitOSContext()()
|
||||
|
||||
newNs, err := netns.GetFromPath(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed get network namespace %q: %v", path, err)
|
||||
}
|
||||
defer newNs.Close()
|
||||
|
||||
// Invoked before the namespace switch happens but after the namespace file
|
||||
// handle is obtained.
|
||||
if err := prefunc(int(newNs)); err != nil {
|
||||
return fmt.Errorf("failed in prefunc: %v", err)
|
||||
}
|
||||
|
||||
if err = netns.Set(newNs); err != nil {
|
||||
return err
|
||||
}
|
||||
defer ns.SetNamespace()
|
||||
|
||||
// Invoked after the namespace switch.
|
||||
return postfunc(ns.ParseHandlerInt())
|
||||
}
|
||||
|
||||
func (n *networkNamespace) nsPath() string {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
return n.path
|
||||
}
|
||||
|
||||
func (n *networkNamespace) Info() Info {
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *networkNamespace) Key() string {
|
||||
return n.path
|
||||
}
|
||||
|
||||
func (n *networkNamespace) Destroy() error {
|
||||
if n.nlHandle != nil {
|
||||
n.nlHandle.Delete()
|
||||
}
|
||||
// Assuming no running process is executing in this network namespace,
|
||||
// unmounting is sufficient to destroy it.
|
||||
if err := syscall.Unmount(n.path, syscall.MNT_DETACH); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Stash it into the garbage collection list
|
||||
addToGarbagePaths(n.path)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Restore restore the network namespace
|
||||
func (n *networkNamespace) Restore(ifsopt map[string][]IfaceOption, routes []*types.StaticRoute, gw net.IP, gw6 net.IP) error {
|
||||
// restore interfaces
|
||||
for name, opts := range ifsopt {
|
||||
if !strings.Contains(name, "+") {
|
||||
return fmt.Errorf("wrong iface name in restore osl sandbox interface: %s", name)
|
||||
}
|
||||
seps := strings.Split(name, "+")
|
||||
srcName := seps[0]
|
||||
dstPrefix := seps[1]
|
||||
i := &nwIface{srcName: srcName, dstName: dstPrefix, ns: n}
|
||||
i.processInterfaceOptions(opts...)
|
||||
if i.master != "" {
|
||||
i.dstMaster = n.findDst(i.master, true)
|
||||
if i.dstMaster == "" {
|
||||
return fmt.Errorf("could not find an appropriate master %q for %q",
|
||||
i.master, i.srcName)
|
||||
}
|
||||
}
|
||||
if n.isDefault {
|
||||
i.dstName = i.srcName
|
||||
} else {
|
||||
links, err := n.nlHandle.LinkList()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retrieve list of links in network namespace %q during restore", n.path)
|
||||
}
|
||||
// due to the docker network connect/disconnect, so the dstName should
|
||||
// restore from the namespace
|
||||
for _, link := range links {
|
||||
addrs, err := n.nlHandle.AddrList(link, netlink.FAMILY_V4)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ifaceName := link.Attrs().Name
|
||||
if strings.HasPrefix(ifaceName, "vxlan") {
|
||||
if i.dstName == "vxlan" {
|
||||
i.dstName = ifaceName
|
||||
break
|
||||
}
|
||||
}
|
||||
// find the interface name by ip
|
||||
if i.address != nil {
|
||||
for _, addr := range addrs {
|
||||
if addr.IPNet.String() == i.address.String() {
|
||||
i.dstName = ifaceName
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
if i.dstName == ifaceName {
|
||||
break
|
||||
}
|
||||
}
|
||||
// This is to find the interface name of the pair in overlay sandbox
|
||||
if strings.HasPrefix(ifaceName, "veth") {
|
||||
if i.master != "" && i.dstName == "veth" {
|
||||
i.dstName = ifaceName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var index int
|
||||
indexStr := strings.TrimPrefix(i.dstName, dstPrefix)
|
||||
if indexStr != "" {
|
||||
index, err = strconv.Atoi(indexStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
index++
|
||||
n.Lock()
|
||||
if index > n.nextIfIndex[dstPrefix] {
|
||||
n.nextIfIndex[dstPrefix] = index
|
||||
}
|
||||
n.iFaces = append(n.iFaces, i)
|
||||
n.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// restore routes
|
||||
for _, r := range routes {
|
||||
n.Lock()
|
||||
n.staticRoutes = append(n.staticRoutes, r)
|
||||
n.Unlock()
|
||||
}
|
||||
|
||||
// restore gateway
|
||||
if len(gw) > 0 {
|
||||
n.Lock()
|
||||
n.gw = gw
|
||||
n.Unlock()
|
||||
}
|
||||
|
||||
if len(gw6) > 0 {
|
||||
n.Lock()
|
||||
n.gwv6 = gw6
|
||||
n.Unlock()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks whether IPv6 needs to be enabled/disabled on the loopback interface
|
||||
func (n *networkNamespace) checkLoV6() {
|
||||
var (
|
||||
enable = false
|
||||
action = "disable"
|
||||
)
|
||||
|
||||
n.Lock()
|
||||
for _, iface := range n.iFaces {
|
||||
if iface.AddressIPv6() != nil {
|
||||
enable = true
|
||||
action = "enable"
|
||||
break
|
||||
}
|
||||
}
|
||||
n.Unlock()
|
||||
|
||||
if n.loV6Enabled == enable {
|
||||
return
|
||||
}
|
||||
|
||||
if err := setIPv6(n.path, "lo", enable); err != nil {
|
||||
logrus.Warnf("Failed to %s IPv6 on loopback interface on network namespace %q: %v", action, n.path, err)
|
||||
}
|
||||
|
||||
n.loV6Enabled = enable
|
||||
}
|
||||
|
||||
func reexecSetIPv6() {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
if len(os.Args) < 3 {
|
||||
logrus.Errorf("invalid number of arguments for %s", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ns, err := netns.GetFromPath(os.Args[1])
|
||||
if err != nil {
|
||||
logrus.Errorf("failed get network namespace %q: %v", os.Args[1], err)
|
||||
os.Exit(2)
|
||||
}
|
||||
defer ns.Close()
|
||||
|
||||
if err = netns.Set(ns); err != nil {
|
||||
logrus.Errorf("setting into container netns %q failed: %v", os.Args[1], err)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
var (
|
||||
action = "disable"
|
||||
value = byte('1')
|
||||
path = fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", os.Args[2])
|
||||
)
|
||||
|
||||
if os.Args[3] == "true" {
|
||||
action = "enable"
|
||||
value = byte('0')
|
||||
}
|
||||
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
logrus.Warnf("file does not exist: %s : %v Has IPv6 been disabled in this node's kernel?", path, err)
|
||||
os.Exit(0)
|
||||
}
|
||||
logrus.Errorf("failed to stat %s : %v", path, err)
|
||||
os.Exit(5)
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(path, []byte{value, '\n'}, 0644); err != nil {
|
||||
logrus.Errorf("failed to %s IPv6 forwarding for container's interface %s: %v", action, os.Args[2], err)
|
||||
os.Exit(4)
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func setIPv6(path, iface string, enable bool) error {
|
||||
cmd := &exec.Cmd{
|
||||
Path: reexec.Self(),
|
||||
Args: append([]string{"set-ipv6"}, path, iface, strconv.FormatBool(enable)),
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
}
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("reexec to set IPv6 failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyOSTweaks applies linux configs on the sandbox
|
||||
func (n *networkNamespace) ApplyOSTweaks(types []SandboxType) {
|
||||
for _, t := range types {
|
||||
switch t {
|
||||
case SandboxTypeLoadBalancer:
|
||||
kernel.ApplyOSTweaks(loadBalancerConfig)
|
||||
}
|
||||
}
|
||||
}
|
17
vendor/github.com/docker/libnetwork/osl/namespace_unsupported.go
generated
vendored
Normal file
17
vendor/github.com/docker/libnetwork/osl/namespace_unsupported.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
// +build !linux,!windows,!freebsd
|
||||
|
||||
package osl
|
||||
|
||||
// GC triggers garbage collection of namespace path right away
|
||||
// and waits for it.
|
||||
func GC() {
|
||||
}
|
||||
|
||||
// GetSandboxForExternalKey returns sandbox object for the supplied path
|
||||
func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// SetBasePath sets the base url prefix for the ns path
|
||||
func SetBasePath(path string) {
|
||||
}
|
38
vendor/github.com/docker/libnetwork/osl/namespace_windows.go
generated
vendored
Normal file
38
vendor/github.com/docker/libnetwork/osl/namespace_windows.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
package osl
|
||||
|
||||
import "testing"
|
||||
|
||||
// GenerateKey generates a sandbox key based on the passed
|
||||
// container id.
|
||||
func GenerateKey(containerID string) string {
|
||||
return containerID
|
||||
}
|
||||
|
||||
// NewSandbox provides a new sandbox instance created in an os specific way
|
||||
// provided a key which uniquely identifies the sandbox
|
||||
func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GC triggers garbage collection of namespace path right away
|
||||
// and waits for it.
|
||||
func GC() {
|
||||
}
|
||||
|
||||
// InitOSContext initializes OS context while configuring network resources
|
||||
func InitOSContext() func() {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
// SetupTestOSContext sets up a separate test OS context in which tests will be executed.
|
||||
func SetupTestOSContext(t *testing.T) func() {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
// SetBasePath sets the base url prefix for the ns path
|
||||
func SetBasePath(path string) {
|
||||
}
|
4
vendor/github.com/docker/libnetwork/osl/neigh_freebsd.go
generated
vendored
Normal file
4
vendor/github.com/docker/libnetwork/osl/neigh_freebsd.go
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
package osl
|
||||
|
||||
// NeighOption is a function option type to set neighbor options
|
||||
type NeighOption func()
|
194
vendor/github.com/docker/libnetwork/osl/neigh_linux.go
generated
vendored
Normal file
194
vendor/github.com/docker/libnetwork/osl/neigh_linux.go
generated
vendored
Normal file
@ -0,0 +1,194 @@
|
||||
package osl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
// NeighborSearchError indicates that the neighbor is already present
|
||||
type NeighborSearchError struct {
|
||||
ip net.IP
|
||||
mac net.HardwareAddr
|
||||
present bool
|
||||
}
|
||||
|
||||
func (n NeighborSearchError) Error() string {
|
||||
return fmt.Sprintf("Search neighbor failed for IP %v, mac %v, present in db:%t", n.ip, n.mac, n.present)
|
||||
}
|
||||
|
||||
// NeighOption is a function option type to set interface options
|
||||
type NeighOption func(nh *neigh)
|
||||
|
||||
type neigh struct {
|
||||
dstIP net.IP
|
||||
dstMac net.HardwareAddr
|
||||
linkName string
|
||||
linkDst string
|
||||
family int
|
||||
}
|
||||
|
||||
func (n *networkNamespace) findNeighbor(dstIP net.IP, dstMac net.HardwareAddr) *neigh {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
for _, nh := range n.neighbors {
|
||||
if nh.dstIP.Equal(dstIP) && bytes.Equal(nh.dstMac, dstMac) {
|
||||
return nh
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *networkNamespace) DeleteNeighbor(dstIP net.IP, dstMac net.HardwareAddr, osDelete bool) error {
|
||||
var (
|
||||
iface netlink.Link
|
||||
err error
|
||||
)
|
||||
|
||||
nh := n.findNeighbor(dstIP, dstMac)
|
||||
if nh == nil {
|
||||
return NeighborSearchError{dstIP, dstMac, false}
|
||||
}
|
||||
|
||||
if osDelete {
|
||||
n.Lock()
|
||||
nlh := n.nlHandle
|
||||
n.Unlock()
|
||||
|
||||
if nh.linkDst != "" {
|
||||
iface, err = nlh.LinkByName(nh.linkDst)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find interface with destination name %s: %v",
|
||||
nh.linkDst, err)
|
||||
}
|
||||
}
|
||||
|
||||
nlnh := &netlink.Neigh{
|
||||
IP: dstIP,
|
||||
State: netlink.NUD_PERMANENT,
|
||||
Family: nh.family,
|
||||
}
|
||||
|
||||
if nlnh.Family > 0 {
|
||||
nlnh.HardwareAddr = dstMac
|
||||
nlnh.Flags = netlink.NTF_SELF
|
||||
}
|
||||
|
||||
if nh.linkDst != "" {
|
||||
nlnh.LinkIndex = iface.Attrs().Index
|
||||
}
|
||||
|
||||
// If the kernel deletion fails for the neighbor entry still remote it
|
||||
// from the namespace cache. Otherwise if the neighbor moves back to the
|
||||
// same host again, kernel update can fail.
|
||||
if err := nlh.NeighDel(nlnh); err != nil {
|
||||
logrus.Warnf("Deleting neighbor IP %s, mac %s failed, %v", dstIP, dstMac, err)
|
||||
}
|
||||
|
||||
// Delete the dynamic entry in the bridge
|
||||
if nlnh.Family > 0 {
|
||||
nlnh := &netlink.Neigh{
|
||||
IP: dstIP,
|
||||
Family: nh.family,
|
||||
}
|
||||
|
||||
nlnh.HardwareAddr = dstMac
|
||||
nlnh.Flags = netlink.NTF_MASTER
|
||||
if nh.linkDst != "" {
|
||||
nlnh.LinkIndex = iface.Attrs().Index
|
||||
}
|
||||
nlh.NeighDel(nlnh)
|
||||
}
|
||||
}
|
||||
|
||||
n.Lock()
|
||||
for i, nh := range n.neighbors {
|
||||
if nh.dstIP.Equal(dstIP) && bytes.Equal(nh.dstMac, dstMac) {
|
||||
n.neighbors = append(n.neighbors[:i], n.neighbors[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
n.Unlock()
|
||||
logrus.Debugf("Neighbor entry deleted for IP %v, mac %v osDelete:%t", dstIP, dstMac, osDelete)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *networkNamespace) AddNeighbor(dstIP net.IP, dstMac net.HardwareAddr, force bool, options ...NeighOption) error {
|
||||
var (
|
||||
iface netlink.Link
|
||||
err error
|
||||
neighborAlreadyPresent bool
|
||||
)
|
||||
|
||||
// If the namespace already has the neighbor entry but the AddNeighbor is called
|
||||
// because of a miss notification (force flag) program the kernel anyway.
|
||||
nh := n.findNeighbor(dstIP, dstMac)
|
||||
if nh != nil {
|
||||
neighborAlreadyPresent = true
|
||||
logrus.Warnf("Neighbor entry already present for IP %v, mac %v neighbor:%+v forceUpdate:%t", dstIP, dstMac, nh, force)
|
||||
if !force {
|
||||
return NeighborSearchError{dstIP, dstMac, true}
|
||||
}
|
||||
}
|
||||
|
||||
nh = &neigh{
|
||||
dstIP: dstIP,
|
||||
dstMac: dstMac,
|
||||
}
|
||||
|
||||
nh.processNeighOptions(options...)
|
||||
|
||||
if nh.linkName != "" {
|
||||
nh.linkDst = n.findDst(nh.linkName, false)
|
||||
if nh.linkDst == "" {
|
||||
return fmt.Errorf("could not find the interface with name %s", nh.linkName)
|
||||
}
|
||||
}
|
||||
|
||||
n.Lock()
|
||||
nlh := n.nlHandle
|
||||
n.Unlock()
|
||||
|
||||
if nh.linkDst != "" {
|
||||
iface, err = nlh.LinkByName(nh.linkDst)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find interface with destination name %s: %v", nh.linkDst, err)
|
||||
}
|
||||
}
|
||||
|
||||
nlnh := &netlink.Neigh{
|
||||
IP: dstIP,
|
||||
HardwareAddr: dstMac,
|
||||
State: netlink.NUD_PERMANENT,
|
||||
Family: nh.family,
|
||||
}
|
||||
|
||||
if nlnh.Family > 0 {
|
||||
nlnh.Flags = netlink.NTF_SELF
|
||||
}
|
||||
|
||||
if nh.linkDst != "" {
|
||||
nlnh.LinkIndex = iface.Attrs().Index
|
||||
}
|
||||
|
||||
if err := nlh.NeighSet(nlnh); err != nil {
|
||||
return fmt.Errorf("could not add neighbor entry:%+v error:%v", nlnh, err)
|
||||
}
|
||||
|
||||
if neighborAlreadyPresent {
|
||||
return nil
|
||||
}
|
||||
|
||||
n.Lock()
|
||||
n.neighbors = append(n.neighbors, nh)
|
||||
n.Unlock()
|
||||
logrus.Debugf("Neighbor entry added for IP:%v, mac:%v on ifc:%s", dstIP, dstMac, nh.linkName)
|
||||
|
||||
return nil
|
||||
}
|
4
vendor/github.com/docker/libnetwork/osl/neigh_windows.go
generated
vendored
Normal file
4
vendor/github.com/docker/libnetwork/osl/neigh_windows.go
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
package osl
|
||||
|
||||
// NeighOption is a function option type to set neighbor options
|
||||
type NeighOption func()
|
73
vendor/github.com/docker/libnetwork/osl/options_linux.go
generated
vendored
Normal file
73
vendor/github.com/docker/libnetwork/osl/options_linux.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
package osl
|
||||
|
||||
import "net"
|
||||
|
||||
func (nh *neigh) processNeighOptions(options ...NeighOption) {
|
||||
for _, opt := range options {
|
||||
if opt != nil {
|
||||
opt(nh)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (n *networkNamespace) LinkName(name string) NeighOption {
|
||||
return func(nh *neigh) {
|
||||
nh.linkName = name
|
||||
}
|
||||
}
|
||||
|
||||
func (n *networkNamespace) Family(family int) NeighOption {
|
||||
return func(nh *neigh) {
|
||||
nh.family = family
|
||||
}
|
||||
}
|
||||
|
||||
func (i *nwIface) processInterfaceOptions(options ...IfaceOption) {
|
||||
for _, opt := range options {
|
||||
if opt != nil {
|
||||
opt(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (n *networkNamespace) Bridge(isBridge bool) IfaceOption {
|
||||
return func(i *nwIface) {
|
||||
i.bridge = isBridge
|
||||
}
|
||||
}
|
||||
|
||||
func (n *networkNamespace) Master(name string) IfaceOption {
|
||||
return func(i *nwIface) {
|
||||
i.master = name
|
||||
}
|
||||
}
|
||||
|
||||
func (n *networkNamespace) MacAddress(mac net.HardwareAddr) IfaceOption {
|
||||
return func(i *nwIface) {
|
||||
i.mac = mac
|
||||
}
|
||||
}
|
||||
|
||||
func (n *networkNamespace) Address(addr *net.IPNet) IfaceOption {
|
||||
return func(i *nwIface) {
|
||||
i.address = addr
|
||||
}
|
||||
}
|
||||
|
||||
func (n *networkNamespace) AddressIPv6(addr *net.IPNet) IfaceOption {
|
||||
return func(i *nwIface) {
|
||||
i.addressIPv6 = addr
|
||||
}
|
||||
}
|
||||
|
||||
func (n *networkNamespace) LinkLocalAddresses(list []*net.IPNet) IfaceOption {
|
||||
return func(i *nwIface) {
|
||||
i.llAddrs = list
|
||||
}
|
||||
}
|
||||
|
||||
func (n *networkNamespace) Routes(routes []*net.IPNet) IfaceOption {
|
||||
return func(i *nwIface) {
|
||||
i.routes = routes
|
||||
}
|
||||
}
|
203
vendor/github.com/docker/libnetwork/osl/route_linux.go
generated
vendored
Normal file
203
vendor/github.com/docker/libnetwork/osl/route_linux.go
generated
vendored
Normal file
@ -0,0 +1,203 @@
|
||||
package osl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func (n *networkNamespace) Gateway() net.IP {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
return n.gw
|
||||
}
|
||||
|
||||
func (n *networkNamespace) GatewayIPv6() net.IP {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
return n.gwv6
|
||||
}
|
||||
|
||||
func (n *networkNamespace) StaticRoutes() []*types.StaticRoute {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
routes := make([]*types.StaticRoute, len(n.staticRoutes))
|
||||
for i, route := range n.staticRoutes {
|
||||
r := route.GetCopy()
|
||||
routes[i] = r
|
||||
}
|
||||
|
||||
return routes
|
||||
}
|
||||
|
||||
func (n *networkNamespace) setGateway(gw net.IP) {
|
||||
n.Lock()
|
||||
n.gw = gw
|
||||
n.Unlock()
|
||||
}
|
||||
|
||||
func (n *networkNamespace) setGatewayIPv6(gwv6 net.IP) {
|
||||
n.Lock()
|
||||
n.gwv6 = gwv6
|
||||
n.Unlock()
|
||||
}
|
||||
|
||||
func (n *networkNamespace) SetGateway(gw net.IP) error {
|
||||
// Silently return if the gateway is empty
|
||||
if len(gw) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := n.programGateway(gw, true)
|
||||
if err == nil {
|
||||
n.setGateway(gw)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *networkNamespace) UnsetGateway() error {
|
||||
gw := n.Gateway()
|
||||
|
||||
// Silently return if the gateway is empty
|
||||
if len(gw) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := n.programGateway(gw, false)
|
||||
if err == nil {
|
||||
n.setGateway(net.IP{})
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *networkNamespace) programGateway(gw net.IP, isAdd bool) error {
|
||||
gwRoutes, err := n.nlHandle.RouteGet(gw)
|
||||
if err != nil {
|
||||
return fmt.Errorf("route for the gateway %s could not be found: %v", gw, err)
|
||||
}
|
||||
|
||||
var linkIndex int
|
||||
for _, gwRoute := range gwRoutes {
|
||||
if gwRoute.Gw == nil {
|
||||
linkIndex = gwRoute.LinkIndex
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if linkIndex == 0 {
|
||||
return fmt.Errorf("Direct route for the gateway %s could not be found", gw)
|
||||
}
|
||||
|
||||
if isAdd {
|
||||
return n.nlHandle.RouteAdd(&netlink.Route{
|
||||
Scope: netlink.SCOPE_UNIVERSE,
|
||||
LinkIndex: linkIndex,
|
||||
Gw: gw,
|
||||
})
|
||||
}
|
||||
|
||||
return n.nlHandle.RouteDel(&netlink.Route{
|
||||
Scope: netlink.SCOPE_UNIVERSE,
|
||||
LinkIndex: linkIndex,
|
||||
Gw: gw,
|
||||
})
|
||||
}
|
||||
|
||||
// Program a route in to the namespace routing table.
|
||||
func (n *networkNamespace) programRoute(path string, dest *net.IPNet, nh net.IP) error {
|
||||
gwRoutes, err := n.nlHandle.RouteGet(nh)
|
||||
if err != nil {
|
||||
return fmt.Errorf("route for the next hop %s could not be found: %v", nh, err)
|
||||
}
|
||||
|
||||
return n.nlHandle.RouteAdd(&netlink.Route{
|
||||
Scope: netlink.SCOPE_UNIVERSE,
|
||||
LinkIndex: gwRoutes[0].LinkIndex,
|
||||
Gw: nh,
|
||||
Dst: dest,
|
||||
})
|
||||
}
|
||||
|
||||
// Delete a route from the namespace routing table.
|
||||
func (n *networkNamespace) removeRoute(path string, dest *net.IPNet, nh net.IP) error {
|
||||
gwRoutes, err := n.nlHandle.RouteGet(nh)
|
||||
if err != nil {
|
||||
return fmt.Errorf("route for the next hop could not be found: %v", err)
|
||||
}
|
||||
|
||||
return n.nlHandle.RouteDel(&netlink.Route{
|
||||
Scope: netlink.SCOPE_UNIVERSE,
|
||||
LinkIndex: gwRoutes[0].LinkIndex,
|
||||
Gw: nh,
|
||||
Dst: dest,
|
||||
})
|
||||
}
|
||||
|
||||
func (n *networkNamespace) SetGatewayIPv6(gwv6 net.IP) error {
|
||||
// Silently return if the gateway is empty
|
||||
if len(gwv6) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := n.programGateway(gwv6, true)
|
||||
if err == nil {
|
||||
n.setGatewayIPv6(gwv6)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *networkNamespace) UnsetGatewayIPv6() error {
|
||||
gwv6 := n.GatewayIPv6()
|
||||
|
||||
// Silently return if the gateway is empty
|
||||
if len(gwv6) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := n.programGateway(gwv6, false)
|
||||
if err == nil {
|
||||
n.Lock()
|
||||
n.gwv6 = net.IP{}
|
||||
n.Unlock()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *networkNamespace) AddStaticRoute(r *types.StaticRoute) error {
|
||||
err := n.programRoute(n.nsPath(), r.Destination, r.NextHop)
|
||||
if err == nil {
|
||||
n.Lock()
|
||||
n.staticRoutes = append(n.staticRoutes, r)
|
||||
n.Unlock()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *networkNamespace) RemoveStaticRoute(r *types.StaticRoute) error {
|
||||
|
||||
err := n.removeRoute(n.nsPath(), r.Destination, r.NextHop)
|
||||
if err == nil {
|
||||
n.Lock()
|
||||
lastIndex := len(n.staticRoutes) - 1
|
||||
for i, v := range n.staticRoutes {
|
||||
if v == r {
|
||||
// Overwrite the route we're removing with the last element
|
||||
n.staticRoutes[i] = n.staticRoutes[lastIndex]
|
||||
// Shorten the slice to trim the extra element
|
||||
n.staticRoutes = n.staticRoutes[:lastIndex]
|
||||
break
|
||||
}
|
||||
}
|
||||
n.Unlock()
|
||||
}
|
||||
return err
|
||||
}
|
187
vendor/github.com/docker/libnetwork/osl/sandbox.go
generated
vendored
Normal file
187
vendor/github.com/docker/libnetwork/osl/sandbox.go
generated
vendored
Normal file
@ -0,0 +1,187 @@
|
||||
// Package osl describes structures and interfaces which abstract os entities
|
||||
package osl
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
// SandboxType specify the time of the sandbox, this can be used to apply special configs
|
||||
type SandboxType int
|
||||
|
||||
const (
|
||||
// SandboxTypeIngress indicates that the sandbox is for the ingress
|
||||
SandboxTypeIngress = iota
|
||||
// SandboxTypeLoadBalancer indicates that the sandbox is a load balancer
|
||||
SandboxTypeLoadBalancer = iota
|
||||
)
|
||||
|
||||
// Sandbox represents a network sandbox, identified by a specific key. It
|
||||
// holds a list of Interfaces, routes etc, and more can be added dynamically.
|
||||
type Sandbox interface {
|
||||
// The path where the network namespace is mounted.
|
||||
Key() string
|
||||
|
||||
// Add an existing Interface to this sandbox. The operation will rename
|
||||
// from the Interface SrcName to DstName as it moves, and reconfigure the
|
||||
// interface according to the specified settings. The caller is expected
|
||||
// to only provide a prefix for DstName. The AddInterface api will auto-generate
|
||||
// an appropriate suffix for the DstName to disambiguate.
|
||||
AddInterface(SrcName string, DstPrefix string, options ...IfaceOption) error
|
||||
|
||||
// Set default IPv4 gateway for the sandbox
|
||||
SetGateway(gw net.IP) error
|
||||
|
||||
// Set default IPv6 gateway for the sandbox
|
||||
SetGatewayIPv6(gw net.IP) error
|
||||
|
||||
// Unset the previously set default IPv4 gateway in the sandbox
|
||||
UnsetGateway() error
|
||||
|
||||
// Unset the previously set default IPv6 gateway in the sandbox
|
||||
UnsetGatewayIPv6() error
|
||||
|
||||
// GetLoopbackIfaceName returns the name of the loopback interface
|
||||
GetLoopbackIfaceName() string
|
||||
|
||||
// AddAliasIP adds the passed IP address to the named interface
|
||||
AddAliasIP(ifName string, ip *net.IPNet) error
|
||||
|
||||
// RemoveAliasIP removes the passed IP address from the named interface
|
||||
RemoveAliasIP(ifName string, ip *net.IPNet) error
|
||||
|
||||
// Add a static route to the sandbox.
|
||||
AddStaticRoute(*types.StaticRoute) error
|
||||
|
||||
// Remove a static route from the sandbox.
|
||||
RemoveStaticRoute(*types.StaticRoute) error
|
||||
|
||||
// AddNeighbor adds a neighbor entry into the sandbox.
|
||||
AddNeighbor(dstIP net.IP, dstMac net.HardwareAddr, force bool, option ...NeighOption) error
|
||||
|
||||
// DeleteNeighbor deletes neighbor entry from the sandbox.
|
||||
DeleteNeighbor(dstIP net.IP, dstMac net.HardwareAddr, osDelete bool) error
|
||||
|
||||
// Returns an interface with methods to set neighbor options.
|
||||
NeighborOptions() NeighborOptionSetter
|
||||
|
||||
// Returns an interface with methods to set interface options.
|
||||
InterfaceOptions() IfaceOptionSetter
|
||||
|
||||
//Invoke
|
||||
InvokeFunc(func()) error
|
||||
|
||||
// Returns an interface with methods to get sandbox state.
|
||||
Info() Info
|
||||
|
||||
// Destroy the sandbox
|
||||
Destroy() error
|
||||
|
||||
// restore sandbox
|
||||
Restore(ifsopt map[string][]IfaceOption, routes []*types.StaticRoute, gw net.IP, gw6 net.IP) error
|
||||
|
||||
// ApplyOSTweaks applies operating system specific knobs on the sandbox
|
||||
ApplyOSTweaks([]SandboxType)
|
||||
}
|
||||
|
||||
// NeighborOptionSetter interface defines the option setter methods for interface options
|
||||
type NeighborOptionSetter interface {
|
||||
// LinkName returns an option setter to set the srcName of the link that should
|
||||
// be used in the neighbor entry
|
||||
LinkName(string) NeighOption
|
||||
|
||||
// Family returns an option setter to set the address family for the neighbor
|
||||
// entry. eg. AF_BRIDGE
|
||||
Family(int) NeighOption
|
||||
}
|
||||
|
||||
// IfaceOptionSetter interface defines the option setter methods for interface options.
|
||||
type IfaceOptionSetter interface {
|
||||
// Bridge returns an option setter to set if the interface is a bridge.
|
||||
Bridge(bool) IfaceOption
|
||||
|
||||
// MacAddress returns an option setter to set the MAC address.
|
||||
MacAddress(net.HardwareAddr) IfaceOption
|
||||
|
||||
// Address returns an option setter to set IPv4 address.
|
||||
Address(*net.IPNet) IfaceOption
|
||||
|
||||
// Address returns an option setter to set IPv6 address.
|
||||
AddressIPv6(*net.IPNet) IfaceOption
|
||||
|
||||
// LinkLocalAddresses returns an option setter to set the link-local IP addresses.
|
||||
LinkLocalAddresses([]*net.IPNet) IfaceOption
|
||||
|
||||
// Master returns an option setter to set the master interface if any for this
|
||||
// interface. The master interface name should refer to the srcname of a
|
||||
// previously added interface of type bridge.
|
||||
Master(string) IfaceOption
|
||||
|
||||
// Address returns an option setter to set interface routes.
|
||||
Routes([]*net.IPNet) IfaceOption
|
||||
}
|
||||
|
||||
// Info represents all possible information that
|
||||
// the driver wants to place in the sandbox which includes
|
||||
// interfaces, routes and gateway
|
||||
type Info interface {
|
||||
// The collection of Interface previously added with the AddInterface
|
||||
// method. Note that this doesn't include network interfaces added in any
|
||||
// other way (such as the default loopback interface which is automatically
|
||||
// created on creation of a sandbox).
|
||||
Interfaces() []Interface
|
||||
|
||||
// IPv4 gateway for the sandbox.
|
||||
Gateway() net.IP
|
||||
|
||||
// IPv6 gateway for the sandbox.
|
||||
GatewayIPv6() net.IP
|
||||
|
||||
// Additional static routes for the sandbox. (Note that directly
|
||||
// connected routes are stored on the particular interface they refer to.)
|
||||
StaticRoutes() []*types.StaticRoute
|
||||
|
||||
// TODO: Add ip tables etc.
|
||||
}
|
||||
|
||||
// Interface represents the settings and identity of a network device. It is
|
||||
// used as a return type for Network.Link, and it is common practice for the
|
||||
// caller to use this information when moving interface SrcName from host
|
||||
// namespace to DstName in a different net namespace with the appropriate
|
||||
// network settings.
|
||||
type Interface interface {
|
||||
// The name of the interface in the origin network namespace.
|
||||
SrcName() string
|
||||
|
||||
// The name that will be assigned to the interface once moves inside a
|
||||
// network namespace. When the caller passes in a DstName, it is only
|
||||
// expected to pass a prefix. The name will modified with an appropriately
|
||||
// auto-generated suffix.
|
||||
DstName() string
|
||||
|
||||
// IPv4 address for the interface.
|
||||
Address() *net.IPNet
|
||||
|
||||
// IPv6 address for the interface.
|
||||
AddressIPv6() *net.IPNet
|
||||
|
||||
// LinkLocalAddresses returns the link-local IP addresses assigned to the interface.
|
||||
LinkLocalAddresses() []*net.IPNet
|
||||
|
||||
// IP routes for the interface.
|
||||
Routes() []*net.IPNet
|
||||
|
||||
// Bridge returns true if the interface is a bridge
|
||||
Bridge() bool
|
||||
|
||||
// Master returns the srcname of the master interface for this interface.
|
||||
Master() string
|
||||
|
||||
// Remove an interface from the sandbox by renaming to original name
|
||||
// and moving it out of the sandbox.
|
||||
Remove() error
|
||||
|
||||
// Statistics returns the statistics for this interface
|
||||
Statistics() (*types.InterfaceStatistics, error)
|
||||
}
|
44
vendor/github.com/docker/libnetwork/osl/sandbox_freebsd.go
generated
vendored
Normal file
44
vendor/github.com/docker/libnetwork/osl/sandbox_freebsd.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
package osl
|
||||
|
||||
import "testing"
|
||||
|
||||
// GenerateKey generates a sandbox key based on the passed
|
||||
// container id.
|
||||
func GenerateKey(containerID string) string {
|
||||
maxLen := 12
|
||||
if len(containerID) < maxLen {
|
||||
maxLen = len(containerID)
|
||||
}
|
||||
|
||||
return containerID[:maxLen]
|
||||
}
|
||||
|
||||
// NewSandbox provides a new sandbox instance created in an os specific way
|
||||
// provided a key which uniquely identifies the sandbox
|
||||
func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetSandboxForExternalKey returns sandbox object for the supplied path
|
||||
func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GC triggers garbage collection of namespace path right away
|
||||
// and waits for it.
|
||||
func GC() {
|
||||
}
|
||||
|
||||
// InitOSContext initializes OS context while configuring network resources
|
||||
func InitOSContext() func() {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
// SetupTestOSContext sets up a separate test OS context in which tests will be executed.
|
||||
func SetupTestOSContext(t *testing.T) func() {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
// SetBasePath sets the base url prefix for the ns path
|
||||
func SetBasePath(path string) {
|
||||
}
|
22
vendor/github.com/docker/libnetwork/osl/sandbox_unsupported.go
generated
vendored
Normal file
22
vendor/github.com/docker/libnetwork/osl/sandbox_unsupported.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// +build !linux,!windows,!freebsd
|
||||
|
||||
package osl
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// ErrNotImplemented is for platforms which don't implement sandbox
|
||||
ErrNotImplemented = errors.New("not implemented")
|
||||
)
|
||||
|
||||
// NewSandbox provides a new sandbox instance created in an os specific way
|
||||
// provided a key which uniquely identifies the sandbox
|
||||
func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
// GenerateKey generates a sandbox key based on the passed
|
||||
// container id.
|
||||
func GenerateKey(containerID string) string {
|
||||
return ""
|
||||
}
|
11
vendor/github.com/docker/libnetwork/resolvconf/dns/resolvconf.go
generated
vendored
11
vendor/github.com/docker/libnetwork/resolvconf/dns/resolvconf.go
generated
vendored
@ -4,10 +4,14 @@ import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// IPLocalhost is a regex patter for localhost IP address range.
|
||||
// IPLocalhost is a regex pattern for IPv4 or IPv6 loopback range.
|
||||
const IPLocalhost = `((127\.([0-9]{1,3}\.){2}[0-9]{1,3})|(::1)$)`
|
||||
|
||||
// IPv4Localhost is a regex pattern for IPv4 localhost address range.
|
||||
const IPv4Localhost = `(127\.([0-9]{1,3}\.){2}[0-9]{1,3})`
|
||||
|
||||
var localhostIPRegexp = regexp.MustCompile(IPLocalhost)
|
||||
var localhostIPv4Regexp = regexp.MustCompile(IPv4Localhost)
|
||||
|
||||
// IsLocalhost returns true if ip matches the localhost IP regular expression.
|
||||
// Used for determining if nameserver settings are being passed which are
|
||||
@ -15,3 +19,8 @@ var localhostIPRegexp = regexp.MustCompile(IPLocalhost)
|
||||
func IsLocalhost(ip string) bool {
|
||||
return localhostIPRegexp.MatchString(ip)
|
||||
}
|
||||
|
||||
// IsIPv4Localhost returns true if ip matches the IPv4 localhost regular expression.
|
||||
func IsIPv4Localhost(ip string) bool {
|
||||
return localhostIPv4Regexp.MatchString(ip)
|
||||
}
|
||||
|
44
vendor/github.com/docker/libnetwork/resolvconf/resolvconf.go
generated
vendored
44
vendor/github.com/docker/libnetwork/resolvconf/resolvconf.go
generated
vendored
@ -8,10 +8,15 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/docker/libnetwork/resolvconf/dns"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultResolvConf points to the default file used for dns configuration on a linux machine
|
||||
DefaultResolvConf = "/etc/resolv.conf"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -25,7 +30,7 @@ var (
|
||||
// -- e.g. other link-local types -- either won't work in containers or are unnecessary.
|
||||
// For readability and sufficiency for Docker purposes this seemed more reasonable than a
|
||||
// 1000+ character regexp with exact and complete IPv6 validation
|
||||
ipv6Address = `([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{0,4})`
|
||||
ipv6Address = `([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{0,4})(%\w+)?`
|
||||
|
||||
localhostNSRegexp = regexp.MustCompile(`(?m)^nameserver\s+` + dns.IPLocalhost + `\s*\n*`)
|
||||
nsIPv6Regexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`)
|
||||
@ -50,15 +55,7 @@ type File struct {
|
||||
|
||||
// Get returns the contents of /etc/resolv.conf and its hash
|
||||
func Get() (*File, error) {
|
||||
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hash, err := ioutils.HashData(bytes.NewReader(resolv))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &File{Content: resolv, Hash: hash}, nil
|
||||
return GetSpecific(DefaultResolvConf)
|
||||
}
|
||||
|
||||
// GetSpecific returns the contents of the user specified resolv.conf file and its hash
|
||||
@ -122,11 +119,11 @@ func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) (*File, error) {
|
||||
}
|
||||
// if the resulting resolvConf has no more nameservers defined, add appropriate
|
||||
// default DNS servers for IPv4 and (optionally) IPv6
|
||||
if len(GetNameservers(cleanedResolvConf, netutils.IP)) == 0 {
|
||||
logrus.Infof("No non-localhost DNS nameservers are left in resolv.conf. Using default external servers : %v", defaultIPv4Dns)
|
||||
if len(GetNameservers(cleanedResolvConf, types.IP)) == 0 {
|
||||
logrus.Infof("No non-localhost DNS nameservers are left in resolv.conf. Using default external servers: %v", defaultIPv4Dns)
|
||||
dns := defaultIPv4Dns
|
||||
if ipv6Enabled {
|
||||
logrus.Infof("IPv6 enabled; Adding default IPv6 external servers : %v", defaultIPv6Dns)
|
||||
logrus.Infof("IPv6 enabled; Adding default IPv6 external servers: %v", defaultIPv6Dns)
|
||||
dns = append(dns, defaultIPv6Dns...)
|
||||
}
|
||||
cleanedResolvConf = append(cleanedResolvConf, []byte("\n"+strings.Join(dns, "\n"))...)
|
||||
@ -158,11 +155,11 @@ func GetNameservers(resolvConf []byte, kind int) []string {
|
||||
nameservers := []string{}
|
||||
for _, line := range getLines(resolvConf, []byte("#")) {
|
||||
var ns [][]byte
|
||||
if kind == netutils.IP {
|
||||
if kind == types.IP {
|
||||
ns = nsRegexp.FindSubmatch(line)
|
||||
} else if kind == netutils.IPv4 {
|
||||
} else if kind == types.IPv4 {
|
||||
ns = nsIPv4Regexpmatch.FindSubmatch(line)
|
||||
} else if kind == netutils.IPv6 {
|
||||
} else if kind == types.IPv6 {
|
||||
ns = nsIPv6Regexpmatch.FindSubmatch(line)
|
||||
}
|
||||
if len(ns) > 0 {
|
||||
@ -177,8 +174,15 @@ func GetNameservers(resolvConf []byte, kind int) []string {
|
||||
// This function's output is intended for net.ParseCIDR
|
||||
func GetNameserversAsCIDR(resolvConf []byte) []string {
|
||||
nameservers := []string{}
|
||||
for _, nameserver := range GetNameservers(resolvConf, netutils.IP) {
|
||||
nameservers = append(nameservers, nameserver+"/32")
|
||||
for _, nameserver := range GetNameservers(resolvConf, types.IP) {
|
||||
var address string
|
||||
// If IPv6, strip zone if present
|
||||
if strings.Contains(nameserver, ":") {
|
||||
address = strings.Split(nameserver, "%")[0] + "/128"
|
||||
} else {
|
||||
address = nameserver + "/32"
|
||||
}
|
||||
nameservers = append(nameservers, address)
|
||||
}
|
||||
return nameservers
|
||||
}
|
||||
|
86
vendor/github.com/docker/libnetwork/types/types.go
generated
vendored
86
vendor/github.com/docker/libnetwork/types/types.go
generated
vendored
@ -7,12 +7,35 @@ import (
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ishidawataru/sctp"
|
||||
)
|
||||
|
||||
// constants for the IP address type
|
||||
const (
|
||||
IP = iota // IPv4 and IPv6
|
||||
IPv4
|
||||
IPv6
|
||||
)
|
||||
|
||||
// EncryptionKey is the libnetwork representation of the key distributed by the lead
|
||||
// manager.
|
||||
type EncryptionKey struct {
|
||||
Subsystem string
|
||||
Algorithm int32
|
||||
Key []byte
|
||||
LamportTime uint64
|
||||
}
|
||||
|
||||
// UUID represents a globally unique ID of various resources like network and endpoint
|
||||
type UUID string
|
||||
|
||||
// TransportPort represent a local Layer 4 endpoint
|
||||
// QosPolicy represents a quality of service policy on an endpoint
|
||||
type QosPolicy struct {
|
||||
MaxEgressBandwidth uint64
|
||||
}
|
||||
|
||||
// TransportPort represents a local Layer 4 endpoint
|
||||
type TransportPort struct {
|
||||
Proto Protocol
|
||||
Port uint16
|
||||
@ -58,7 +81,7 @@ func (t *TransportPort) FromString(s string) error {
|
||||
return BadRequestErrorf("invalid format for transport port: %s", s)
|
||||
}
|
||||
|
||||
// PortBinding represent a port binding between the container and the host
|
||||
// PortBinding represents a port binding between the container and the host
|
||||
type PortBinding struct {
|
||||
Proto Protocol
|
||||
IP net.IP
|
||||
@ -75,6 +98,8 @@ func (p PortBinding) HostAddr() (net.Addr, error) {
|
||||
return &net.UDPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
|
||||
case TCP:
|
||||
return &net.TCPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
|
||||
case SCTP:
|
||||
return &sctp.SCTPAddr{IP: []net.IP{p.HostIP}, Port: int(p.HostPort)}, nil
|
||||
default:
|
||||
return nil, ErrInvalidProtocolBinding(p.Proto.String())
|
||||
}
|
||||
@ -87,6 +112,8 @@ func (p PortBinding) ContainerAddr() (net.Addr, error) {
|
||||
return &net.UDPAddr{IP: p.IP, Port: int(p.Port)}, nil
|
||||
case TCP:
|
||||
return &net.TCPAddr{IP: p.IP, Port: int(p.Port)}, nil
|
||||
case SCTP:
|
||||
return &sctp.SCTPAddr{IP: []net.IP{p.IP}, Port: int(p.Port)}, nil
|
||||
default:
|
||||
return nil, ErrInvalidProtocolBinding(p.Proto.String())
|
||||
}
|
||||
@ -104,21 +131,26 @@ func (p *PortBinding) GetCopy() PortBinding {
|
||||
}
|
||||
}
|
||||
|
||||
// String return the PortBinding structure in string form
|
||||
// String returns the PortBinding structure in string form
|
||||
func (p *PortBinding) String() string {
|
||||
ret := fmt.Sprintf("%s/", p.Proto)
|
||||
if p.IP != nil {
|
||||
ret = fmt.Sprintf("%s%s", ret, p.IP.String())
|
||||
ret += p.IP.String()
|
||||
}
|
||||
ret = fmt.Sprintf("%s:%d/", ret, p.Port)
|
||||
if p.HostIP != nil {
|
||||
ret = fmt.Sprintf("%s%s", ret, p.HostIP.String())
|
||||
ret += p.HostIP.String()
|
||||
}
|
||||
ret = fmt.Sprintf("%s:%d", ret, p.HostPort)
|
||||
return ret
|
||||
}
|
||||
|
||||
// FromString reads the TransportPort structure from string
|
||||
// FromString reads the PortBinding structure from string s.
|
||||
// String s is a triple of "protocol/containerIP:port/hostIP:port"
|
||||
// containerIP and hostIP can be in dotted decimal ("192.0.2.1") or IPv6 ("2001:db8::68") form.
|
||||
// Zoned addresses ("169.254.0.23%eth0" or "fe80::1ff:fe23:4567:890a%eth0") are not supported.
|
||||
// If string s is incorrectly formatted or the IP addresses or ports cannot be parsed, FromString
|
||||
// returns an error.
|
||||
func (p *PortBinding) FromString(s string) error {
|
||||
ps := strings.Split(s, "/")
|
||||
if len(ps) != 3 {
|
||||
@ -140,21 +172,19 @@ func (p *PortBinding) FromString(s string) error {
|
||||
}
|
||||
|
||||
func parseIPPort(s string) (net.IP, uint16, error) {
|
||||
pp := strings.Split(s, ":")
|
||||
if len(pp) != 2 {
|
||||
return nil, 0, BadRequestErrorf("invalid format: %s", s)
|
||||
}
|
||||
|
||||
var ip net.IP
|
||||
if pp[0] != "" {
|
||||
if ip = net.ParseIP(pp[0]); ip == nil {
|
||||
return nil, 0, BadRequestErrorf("invalid ip: %s", pp[0])
|
||||
}
|
||||
}
|
||||
|
||||
port, err := strconv.ParseUint(pp[1], 10, 16)
|
||||
hoststr, portstr, err := net.SplitHostPort(s)
|
||||
if err != nil {
|
||||
return nil, 0, BadRequestErrorf("invalid port: %s", pp[1])
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
ip := net.ParseIP(hoststr)
|
||||
if ip == nil {
|
||||
return nil, 0, BadRequestErrorf("invalid ip: %s", hoststr)
|
||||
}
|
||||
|
||||
port, err := strconv.ParseUint(portstr, 10, 16)
|
||||
if err != nil {
|
||||
return nil, 0, BadRequestErrorf("invalid port: %s", portstr)
|
||||
}
|
||||
|
||||
return ip, uint16(port), nil
|
||||
@ -212,9 +242,11 @@ const (
|
||||
TCP = 6
|
||||
// UDP is for the UDP ip protocol
|
||||
UDP = 17
|
||||
// SCTP is for the SCTP ip protocol
|
||||
SCTP = 132
|
||||
)
|
||||
|
||||
// Protocol represents a IP protocol number
|
||||
// Protocol represents an IP protocol number
|
||||
type Protocol uint8
|
||||
|
||||
func (p Protocol) String() string {
|
||||
@ -225,6 +257,8 @@ func (p Protocol) String() string {
|
||||
return "tcp"
|
||||
case UDP:
|
||||
return "udp"
|
||||
case SCTP:
|
||||
return "sctp"
|
||||
default:
|
||||
return fmt.Sprintf("%d", p)
|
||||
}
|
||||
@ -239,6 +273,8 @@ func ParseProtocol(s string) Protocol {
|
||||
return UDP
|
||||
case "tcp":
|
||||
return TCP
|
||||
case "sctp":
|
||||
return SCTP
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
@ -296,6 +332,8 @@ func CompareIPNet(a, b *net.IPNet) bool {
|
||||
}
|
||||
|
||||
// GetMinimalIP returns the address in its shortest form
|
||||
// If ip contains an IPv4-mapped IPv6 address, the 4-octet form of the IPv4 address will be returned.
|
||||
// Otherwise ip is returned unchanged.
|
||||
func GetMinimalIP(ip net.IP) net.IP {
|
||||
if ip != nil && ip.To4() != nil {
|
||||
return ip.To4()
|
||||
@ -318,6 +356,12 @@ func GetMinimalIPNet(nw *net.IPNet) *net.IPNet {
|
||||
return nw
|
||||
}
|
||||
|
||||
// IsIPNetValid returns true if the ipnet is a valid network/mask
|
||||
// combination. Otherwise returns false.
|
||||
func IsIPNetValid(nw *net.IPNet) bool {
|
||||
return nw.String() != "0.0.0.0/0"
|
||||
}
|
||||
|
||||
var v4inV6MaskPrefix = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
||||
|
||||
// compareIPMask checks if the passed ip and mask are semantically compatible.
|
||||
|
50
vendor/github.com/docker/libnetwork/vendor.conf
generated
vendored
Normal file
50
vendor/github.com/docker/libnetwork/vendor.conf
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
|
||||
github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
|
||||
github.com/Microsoft/go-winio v0.4.11
|
||||
github.com/Microsoft/hcsshim v0.7.3
|
||||
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
||||
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
|
||||
github.com/codegangsta/cli a65b733b303f0055f8d324d805f393cd3e7a7904
|
||||
github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b
|
||||
github.com/coreos/etcd v3.2.1
|
||||
github.com/coreos/go-semver v0.2.0
|
||||
github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
|
||||
go.etcd.io/bbolt v1.3.1-etcd.8
|
||||
|
||||
github.com/docker/docker 162ba6016def672690ee4a1f3978368853a1e149
|
||||
github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
|
||||
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
|
||||
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
|
||||
github.com/docker/libkv 458977154600b9f23984d9f4b82e79570b5ae12b
|
||||
|
||||
github.com/godbus/dbus v4.0.0
|
||||
github.com/gogo/protobuf v1.0.0
|
||||
github.com/gorilla/context v1.1
|
||||
github.com/gorilla/mux v1.1
|
||||
github.com/hashicorp/consul v0.5.2
|
||||
github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
||||
github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e
|
||||
github.com/hashicorp/memberlist 3d8438da9589e7b608a83ffac1ef8211486bcb7c
|
||||
github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372
|
||||
github.com/hashicorp/go-sockaddr 6d291a969b86c4b633730bfc6b8b9d64c3aafed9
|
||||
github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
|
||||
github.com/mattn/go-shellwords v1.0.3
|
||||
github.com/miekg/dns v1.0.7
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1
|
||||
github.com/opencontainers/image-spec v1.0.1
|
||||
github.com/opencontainers/runc 69663f0bd4b60df09991c08812a60108003fa340
|
||||
github.com/opencontainers/runtime-spec v1.0.1
|
||||
github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
|
||||
github.com/sirupsen/logrus v1.0.3
|
||||
github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
|
||||
github.com/vishvananda/netlink b2de5d10e38ecce8607e6b438b6d174f389a004e
|
||||
github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
|
||||
golang.org/x/crypto 1a580b3eff7814fc9b40602fd35256c63b50f491
|
||||
golang.org/x/net 0ed95abb35c445290478a5348a7b38bb154135fd
|
||||
golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd
|
||||
golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
|
||||
github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
|
||||
github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb
|
||||
|
||||
gotest.tools v2.1.0
|
||||
github.com/google/go-cmp v0.2.0
|
Reference in New Issue
Block a user