mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Vendoring libnetwork
Vendoring libnetwork commit: 8fb0a8bc9e3166216ca3da2d0bb15332f6685745 - Fixes breakage in k/v store handling logic in experimental - Adds back all the fixes that went in 1.7.1 to master - Change VXLAN port in overlay driver to IANA assigned port Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
parent
58edd21c05
commit
c6dc6bcbb8
32 changed files with 354 additions and 142 deletions
|
@ -18,14 +18,14 @@ clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://gith
|
||||||
clone hg code.google.com/p/gosqlite 74691fb6f837
|
clone hg code.google.com/p/gosqlite 74691fb6f837
|
||||||
|
|
||||||
#get libnetwork packages
|
#get libnetwork packages
|
||||||
clone git github.com/docker/libnetwork 4c14cd316f40f16bc1c17e420b18a1902dc575a7
|
clone git github.com/docker/libnetwork 0517ceae7dea82ded435b99af810efa27b56de73
|
||||||
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
||||||
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
||||||
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
||||||
clone git github.com/hashicorp/serf 7151adcef72687bf95f451a2e0ba15cb19412bf2
|
clone git github.com/hashicorp/serf 7151adcef72687bf95f451a2e0ba15cb19412bf2
|
||||||
clone git github.com/docker/libkv e8cde779d58273d240c1eff065352a6cd67027dd
|
clone git github.com/docker/libkv 60c7c881345b3c67defc7f93a8297debf041d43c
|
||||||
clone git github.com/vishvananda/netns 5478c060110032f972e86a1f844fdb9a2f008f2c
|
clone git github.com/vishvananda/netns 493029407eeb434d0c2d44e02ea072ff2488d322
|
||||||
clone git github.com/vishvananda/netlink 8eb64238879fed52fd51c5b30ad20b928fb4c36c
|
clone git github.com/vishvananda/netlink 20397a138846e4d6590e01783ed023ed7e1c38a6
|
||||||
clone git github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
|
clone git github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
|
||||||
clone git github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
|
clone git github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
|
||||||
clone git github.com/coreos/go-etcd v2.0.0
|
clone git github.com/coreos/go-etcd v2.0.0
|
||||||
|
|
|
@ -11,8 +11,8 @@ sudo: false
|
||||||
before_install:
|
before_install:
|
||||||
# Symlink below is needed for Travis CI to work correctly on personal forks of libkv
|
# Symlink below is needed for Travis CI to work correctly on personal forks of libkv
|
||||||
- ln -s $HOME/gopath/src/github.com/${TRAVIS_REPO_SLUG///libkv/} $HOME/gopath/src/github.com/docker
|
- ln -s $HOME/gopath/src/github.com/${TRAVIS_REPO_SLUG///libkv/} $HOME/gopath/src/github.com/docker
|
||||||
- go get code.google.com/p/go.tools/cmd/vet
|
- go get golang.org/x/tools/cmd/vet
|
||||||
- go get code.google.com/p/go.tools/cmd/cover
|
- go get golang.org/x/tools/cmd/cover
|
||||||
- go get github.com/mattn/goveralls
|
- go get github.com/mattn/goveralls
|
||||||
- go get github.com/golang/lint/golint
|
- go get github.com/golang/lint/golint
|
||||||
- go get github.com/GeertJohan/fgt
|
- go get github.com/GeertJohan/fgt
|
||||||
|
|
|
@ -99,8 +99,9 @@ func (s *Consul) refreshSession(pair *api.KVPair) error {
|
||||||
|
|
||||||
if session == "" {
|
if session == "" {
|
||||||
entry := &api.SessionEntry{
|
entry := &api.SessionEntry{
|
||||||
Behavior: api.SessionBehaviorDelete,
|
Behavior: api.SessionBehaviorDelete, // Delete the key when the session expires
|
||||||
TTL: s.ephemeralTTL.String(),
|
TTL: ((s.ephemeralTTL) / 2).String(), // Consul multiplies the TTL by 2x
|
||||||
|
LockDelay: 1 * time.Millisecond, // Virtually disable lock delay
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the key session
|
// Create the key session
|
||||||
|
@ -108,19 +109,19 @@ func (s *Consul) refreshSession(pair *api.KVPair) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
lockOpts := &api.LockOptions{
|
lockOpts := &api.LockOptions{
|
||||||
Key: pair.Key,
|
Key: pair.Key,
|
||||||
Session: session,
|
Session: session,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock and ignore if lock is held
|
// Lock and ignore if lock is held
|
||||||
// It's just a placeholder for the
|
// It's just a placeholder for the
|
||||||
// ephemeral behavior
|
// ephemeral behavior
|
||||||
lock, _ := s.client.LockOpts(lockOpts)
|
lock, _ := s.client.LockOpts(lockOpts)
|
||||||
if lock != nil {
|
if lock != nil {
|
||||||
lock.Lock(nil)
|
lock.Lock(nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = s.client.Session().Renew(session, nil)
|
_, _, err = s.client.Session().Renew(session, nil)
|
||||||
|
@ -321,18 +322,18 @@ func (s *Consul) WatchTree(directory string, stopCh <-chan struct{}) (<-chan []*
|
||||||
opts.WaitIndex = meta.LastIndex
|
opts.WaitIndex = meta.LastIndex
|
||||||
|
|
||||||
// Return children KV pairs to the channel
|
// Return children KV pairs to the channel
|
||||||
kv := []*store.KVPair{}
|
kvpairs := []*store.KVPair{}
|
||||||
for _, pair := range pairs {
|
for _, pair := range pairs {
|
||||||
if pair.Key == directory {
|
if pair.Key == directory {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
kv = append(kv, &store.KVPair{
|
kvpairs = append(kvpairs, &store.KVPair{
|
||||||
Key: pair.Key,
|
Key: pair.Key,
|
||||||
Value: pair.Value,
|
Value: pair.Value,
|
||||||
LastIndex: pair.ModifyIndex,
|
LastIndex: pair.ModifyIndex,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
watchCh <- kv
|
watchCh <- kvpairs
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -374,11 +375,16 @@ func (l *consulLock) Unlock() error {
|
||||||
// AtomicPut put a value at "key" if the key has not been
|
// AtomicPut put a value at "key" if the key has not been
|
||||||
// modified in the meantime, throws an error if this is the case
|
// modified in the meantime, throws an error if this is the case
|
||||||
func (s *Consul) AtomicPut(key string, value []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
|
func (s *Consul) AtomicPut(key string, value []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
|
||||||
|
|
||||||
|
p := &api.KVPair{Key: s.normalize(key), Value: value}
|
||||||
|
|
||||||
if previous == nil {
|
if previous == nil {
|
||||||
return false, nil, store.ErrPreviousNotSpecified
|
// Consul interprets ModifyIndex = 0 as new key.
|
||||||
|
p.ModifyIndex = 0
|
||||||
|
} else {
|
||||||
|
p.ModifyIndex = previous.LastIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &api.KVPair{Key: s.normalize(key), Value: value, ModifyIndex: previous.LastIndex}
|
|
||||||
if work, _, err := s.client.KV().CAS(p, nil); err != nil {
|
if work, _, err := s.client.KV().CAS(p, nil); err != nil {
|
||||||
return false, nil, err
|
return false, nil, err
|
||||||
} else if !work {
|
} else if !work {
|
||||||
|
|
|
@ -278,11 +278,32 @@ func (s *Etcd) WatchTree(directory string, stopCh <-chan struct{}) (<-chan []*st
|
||||||
// AtomicPut put a value at "key" if the key has not been
|
// AtomicPut put a value at "key" if the key has not been
|
||||||
// modified in the meantime, throws an error if this is the case
|
// modified in the meantime, throws an error if this is the case
|
||||||
func (s *Etcd) AtomicPut(key string, value []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
|
func (s *Etcd) AtomicPut(key string, value []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
|
||||||
if previous == nil {
|
|
||||||
return false, nil, store.ErrPreviousNotSpecified
|
|
||||||
}
|
|
||||||
|
|
||||||
meta, err := s.client.CompareAndSwap(store.Normalize(key), string(value), 0, "", previous.LastIndex)
|
var meta *etcd.Response
|
||||||
|
var err error
|
||||||
|
if previous != nil {
|
||||||
|
meta, err = s.client.CompareAndSwap(store.Normalize(key), string(value), 0, "", previous.LastIndex)
|
||||||
|
} else {
|
||||||
|
// Interpret previous == nil as Atomic Create
|
||||||
|
meta, err = s.client.Create(store.Normalize(key), string(value), 0)
|
||||||
|
if etcdError, ok := err.(*etcd.EtcdError); ok {
|
||||||
|
|
||||||
|
// Directory doesn't exist.
|
||||||
|
if etcdError.ErrorCode == 104 {
|
||||||
|
// Remove the last element (the actual key)
|
||||||
|
// and create the full directory path
|
||||||
|
err = s.createDirectory(store.GetDirectory(key))
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that the directory is created, create the key
|
||||||
|
if _, err := s.client.Create(key, string(value), 0); err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if etcdError, ok := err.(*etcd.EtcdError); ok {
|
if etcdError, ok := err.(*etcd.EtcdError); ok {
|
||||||
// Compare Failed
|
// Compare Failed
|
||||||
|
|
|
@ -11,11 +11,11 @@ type Backend string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// CONSUL backend
|
// CONSUL backend
|
||||||
CONSUL = "consul"
|
CONSUL Backend = "consul"
|
||||||
// ETCD backend
|
// ETCD backend
|
||||||
ETCD = "etcd"
|
ETCD Backend = "etcd"
|
||||||
// ZK backend
|
// ZK backend
|
||||||
ZK = "zk"
|
ZK Backend = "zk"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -77,7 +77,8 @@ type Store interface {
|
||||||
// DeleteTree deletes a range of keys under a given directory
|
// DeleteTree deletes a range of keys under a given directory
|
||||||
DeleteTree(directory string) error
|
DeleteTree(directory string) error
|
||||||
|
|
||||||
// Atomic operation on a single value
|
// Atomic CAS operation on a single value.
|
||||||
|
// Pass previous = nil to create a new key.
|
||||||
AtomicPut(key string, value []byte, previous *KVPair, options *WriteOptions) (bool, *KVPair, error)
|
AtomicPut(key string, value []byte, previous *KVPair, options *WriteOptions) (bool, *KVPair, error)
|
||||||
|
|
||||||
// Atomic delete of a single value
|
// Atomic delete of a single value
|
||||||
|
|
|
@ -265,23 +265,47 @@ func (s *Zookeeper) DeleteTree(directory string) error {
|
||||||
// AtomicPut put a value at "key" if the key has not been
|
// AtomicPut put a value at "key" if the key has not been
|
||||||
// modified in the meantime, throws an error if this is the case
|
// modified in the meantime, throws an error if this is the case
|
||||||
func (s *Zookeeper) AtomicPut(key string, value []byte, previous *store.KVPair, _ *store.WriteOptions) (bool, *store.KVPair, error) {
|
func (s *Zookeeper) AtomicPut(key string, value []byte, previous *store.KVPair, _ *store.WriteOptions) (bool, *store.KVPair, error) {
|
||||||
if previous == nil {
|
|
||||||
return false, nil, store.ErrPreviousNotSpecified
|
|
||||||
}
|
|
||||||
|
|
||||||
meta, err := s.client.Set(store.Normalize(key), value, int32(previous.LastIndex))
|
var lastIndex uint64
|
||||||
if err != nil {
|
if previous != nil {
|
||||||
// Compare Failed
|
meta, err := s.client.Set(store.Normalize(key), value, int32(previous.LastIndex))
|
||||||
if err == zk.ErrBadVersion {
|
if err != nil {
|
||||||
return false, nil, store.ErrKeyModified
|
// Compare Failed
|
||||||
|
if err == zk.ErrBadVersion {
|
||||||
|
return false, nil, store.ErrKeyModified
|
||||||
|
}
|
||||||
|
return false, nil, err
|
||||||
}
|
}
|
||||||
return false, nil, err
|
lastIndex = uint64(meta.Version)
|
||||||
|
} else {
|
||||||
|
// Interpret previous == nil as create operation.
|
||||||
|
_, err := s.client.Create(store.Normalize(key), value, 0, zk.WorldACL(zk.PermAll))
|
||||||
|
if err != nil {
|
||||||
|
// Zookeeper will complain if the directory doesn't exist.
|
||||||
|
if err == zk.ErrNoNode {
|
||||||
|
// Create the directory
|
||||||
|
parts := store.SplitKey(key)
|
||||||
|
parts = parts[:len(parts)-1]
|
||||||
|
if err = s.createFullPath(parts, false); err != nil {
|
||||||
|
// Failed to create the directory.
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
if _, err := s.client.Create(store.Normalize(key), value, 0, zk.WorldACL(zk.PermAll)); err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Unhandled error
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastIndex = 0 // Newly created nodes have version 0.
|
||||||
}
|
}
|
||||||
|
|
||||||
pair := &store.KVPair{
|
pair := &store.KVPair{
|
||||||
Key: key,
|
Key: key,
|
||||||
Value: value,
|
Value: value,
|
||||||
LastIndex: uint64(meta.Version),
|
LastIndex: lastIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, pair, nil
|
return true, pair, nil
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
# Roadmap
|
# Roadmap
|
||||||
|
|
||||||
Libnetwork is a young project and is still being defined.
|
This document defines the high-level goals of the libnetwork project. See [Project Planning](#project-planning) for information on Releases.
|
||||||
This document defines the high-level goals of the project and defines the release-relationship to the Docker Platform.
|
|
||||||
|
|
||||||
* [Goals](#goals)
|
|
||||||
* [Project Planning](#project-planning): release-relationship to the Docker Platform.
|
|
||||||
|
|
||||||
## Long-term Goal
|
## Long-term Goal
|
||||||
|
|
||||||
|
@ -18,12 +14,7 @@ libnetwork aims to satisfy that composable need for Networking in Containers.
|
||||||
- Define a flexible model that allows local and remote drivers to provide networking to containers
|
- Define a flexible model that allows local and remote drivers to provide networking to containers
|
||||||
- Provide a stand-alone tool "dnet" for managing and testing libnetwork
|
- Provide a stand-alone tool "dnet" for managing and testing libnetwork
|
||||||
|
|
||||||
## Project Planning
|
Project Planning
|
||||||
|
================
|
||||||
|
|
||||||
Libnetwork versions do not map 1:1 with Docker Platform releases.
|
[Project Pages](https://github.com/docker/libnetwork/wiki) define the goals for each Milestone and identify the release-relationship to the Docker Platform.
|
||||||
Milestones and Project Pages are used to define the set of features that are included in each release.
|
|
||||||
|
|
||||||
| Platform Version | Libnetwork Version | Planning |
|
|
||||||
|------------------|--------------------|----------|
|
|
||||||
| Docker 1.7 | [0.3](https://github.com/docker/libnetwork/milestones/0.3) | [Project Page](https://github.com/docker/libnetwork/wiki/Docker-1.7-Project-Page) |
|
|
||||||
| Docker 1.8 | [1.0](https://github.com/docker/libnetwork/milestones/1.0) | [Project Page](https://github.com/docker/libnetwork/wiki/Docker-1.8-Project-Page) |
|
|
||||||
|
|
|
@ -55,12 +55,11 @@ func NewHandle(app string, ds datastore.DataStore, id string, numElements uint32
|
||||||
h.watchForChanges()
|
h.watchForChanges()
|
||||||
|
|
||||||
// Get the initial status from the ds if present.
|
// Get the initial status from the ds if present.
|
||||||
err := h.store.GetObject(datastore.Key(h.Key()...), h)
|
if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
|
||||||
if err != datastore.ErrKeyNotFound {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return h, err
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sequence reresents a recurring sequence of 32 bits long bitmasks
|
// Sequence reresents a recurring sequence of 32 bits long bitmasks
|
||||||
|
|
|
@ -40,7 +40,12 @@ func (h *Handle) Value() []byte {
|
||||||
|
|
||||||
// SetValue unmarshals the data from the KV store
|
// SetValue unmarshals the data from the KV store
|
||||||
func (h *Handle) SetValue(value []byte) error {
|
func (h *Handle) SetValue(value []byte) error {
|
||||||
return h.FromByteArray(value)
|
var b []byte
|
||||||
|
if err := json.Unmarshal(value, &b); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return h.FromByteArray(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Index returns the latest DB Index as seen by this object
|
// Index returns the latest DB Index as seen by this object
|
||||||
|
|
|
@ -2,12 +2,14 @@ package bridge
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
bri "github.com/docker/libcontainer/netlink"
|
||||||
"github.com/docker/libnetwork/driverapi"
|
"github.com/docker/libnetwork/driverapi"
|
||||||
"github.com/docker/libnetwork/ipallocator"
|
"github.com/docker/libnetwork/ipallocator"
|
||||||
"github.com/docker/libnetwork/iptables"
|
"github.com/docker/libnetwork/iptables"
|
||||||
|
@ -754,6 +756,20 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addToBridge(ifaceName, bridgeName string) error {
|
||||||
|
iface, err := net.InterfaceByName(ifaceName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not find interface %s: %v", ifaceName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
master, err := net.InterfaceByName(bridgeName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not find bridge %s: %v", bridgeName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bri.AddToBridge(iface, master)
|
||||||
|
}
|
||||||
|
|
||||||
func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
||||||
var (
|
var (
|
||||||
ipv6Addr *net.IPNet
|
ipv6Addr *net.IPNet
|
||||||
|
@ -821,27 +837,27 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Generate a name for what will be the host side pipe interface
|
// Generate a name for what will be the host side pipe interface
|
||||||
name1, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
|
hostIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a name for what will be the sandbox side pipe interface
|
// Generate a name for what will be the sandbox side pipe interface
|
||||||
name2, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
|
containerIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate and add the interface pipe host <-> sandbox
|
// Generate and add the interface pipe host <-> sandbox
|
||||||
veth := &netlink.Veth{
|
veth := &netlink.Veth{
|
||||||
LinkAttrs: netlink.LinkAttrs{Name: name1, TxQLen: 0},
|
LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0},
|
||||||
PeerName: name2}
|
PeerName: containerIfName}
|
||||||
if err = netlink.LinkAdd(veth); err != nil {
|
if err = netlink.LinkAdd(veth); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the host side pipe interface handler
|
// Get the host side pipe interface handler
|
||||||
host, err := netlink.LinkByName(name1)
|
host, err := netlink.LinkByName(hostIfName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -852,7 +868,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Get the sandbox side pipe interface handler
|
// Get the sandbox side pipe interface handler
|
||||||
sbox, err := netlink.LinkByName(name2)
|
sbox, err := netlink.LinkByName(containerIfName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -879,9 +895,8 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach host side pipe interface into the bridge
|
// Attach host side pipe interface into the bridge
|
||||||
if err = netlink.LinkSetMaster(host,
|
if err = addToBridge(hostIfName, config.BridgeName); err != nil {
|
||||||
&netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: config.BridgeName}}); err != nil {
|
return fmt.Errorf("adding interface %s to bridge %s failed: %v", hostIfName, config.BridgeName, err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !config.EnableUserlandProxy {
|
if !config.EnableUserlandProxy {
|
||||||
|
@ -898,14 +913,24 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
||||||
}
|
}
|
||||||
ipv4Addr := &net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
|
ipv4Addr := &net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
|
||||||
|
|
||||||
|
// Down the interface before configuring mac address.
|
||||||
|
if err := netlink.LinkSetDown(sbox); err != nil {
|
||||||
|
return fmt.Errorf("could not set link down for container interface %s: %v", containerIfName, err)
|
||||||
|
}
|
||||||
|
|
||||||
// Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP.
|
// Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP.
|
||||||
mac := electMacAddress(epConfig, ip4)
|
mac := electMacAddress(epConfig, ip4)
|
||||||
err = netlink.LinkSetHardwareAddr(sbox, mac)
|
err = netlink.LinkSetHardwareAddr(sbox, mac)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("could not set mac address for container interface %s: %v", containerIfName, err)
|
||||||
}
|
}
|
||||||
endpoint.macAddress = mac
|
endpoint.macAddress = mac
|
||||||
|
|
||||||
|
// Up the host interface after finishing all netlink configuration
|
||||||
|
if err := netlink.LinkSetUp(host); err != nil {
|
||||||
|
return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err)
|
||||||
|
}
|
||||||
|
|
||||||
// v6 address for the sandbox side pipe interface
|
// v6 address for the sandbox side pipe interface
|
||||||
ipv6Addr = &net.IPNet{}
|
ipv6Addr = &net.IPNet{}
|
||||||
if config.EnableIPv6 {
|
if config.EnableIPv6 {
|
||||||
|
@ -934,7 +959,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the sandbox side pipe interface
|
// Create the sandbox side pipe interface
|
||||||
endpoint.srcName = name2
|
endpoint.srcName = containerIfName
|
||||||
endpoint.addr = ipv4Addr
|
endpoint.addr = ipv4Addr
|
||||||
|
|
||||||
if config.EnableIPv6 {
|
if config.EnableIPv6 {
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
package bridge
|
package bridge
|
||||||
|
|
||||||
import (
|
import (
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/docker/pkg/parsers/kernel"
|
"github.com/docker/docker/pkg/parsers/kernel"
|
||||||
"github.com/docker/libnetwork/netutils"
|
bri "github.com/docker/libcontainer/netlink"
|
||||||
"github.com/docker/libnetwork/types"
|
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetupDevice create a new bridge interface/
|
// SetupDevice create a new bridge interface/
|
||||||
func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
|
func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
|
||||||
|
var setMac bool
|
||||||
|
|
||||||
// We only attempt to create the bridge when the requested device name is
|
// We only attempt to create the bridge when the requested device name is
|
||||||
// the default one.
|
// the default one.
|
||||||
if config.BridgeName != DefaultBridgeName && !config.AllowNonDefaultBridge {
|
if config.BridgeName != DefaultBridgeName && !config.AllowNonDefaultBridge {
|
||||||
|
@ -27,15 +27,10 @@ func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
|
||||||
// was not supported before that.
|
// was not supported before that.
|
||||||
kv, err := kernel.GetKernelVersion()
|
kv, err := kernel.GetKernelVersion()
|
||||||
if err == nil && (kv.Kernel >= 3 && kv.Major >= 3) {
|
if err == nil && (kv.Kernel >= 3 && kv.Major >= 3) {
|
||||||
i.Link.Attrs().HardwareAddr = netutils.GenerateRandomMAC()
|
setMac = true
|
||||||
log.Debugf("Setting bridge mac address to %s", i.Link.Attrs().HardwareAddr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call out to netlink to create the device.
|
return bri.CreateBridge(config.BridgeName, setMac)
|
||||||
if err = netlink.LinkAdd(i.Link); err != nil {
|
|
||||||
return types.InternalErrorf("Failed to program bridge link: %s", err.Error())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetupDeviceUp ups the given bridge interface.
|
// SetupDeviceUp ups the given bridge interface.
|
||||||
|
|
|
@ -57,7 +57,11 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
|
||||||
|
|
||||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||||
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||||
return (jinfo.SetHostsPath("/etc/hosts"))
|
if err := jinfo.SetHostsPath("/etc/hosts"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return jinfo.SetResolvConfPath("/etc/resolv.conf")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||||
|
|
|
@ -155,7 +155,7 @@ func (n *network) initSandbox() error {
|
||||||
|
|
||||||
func (n *network) watchMiss(nlSock *nl.NetlinkSocket) {
|
func (n *network) watchMiss(nlSock *nl.NetlinkSocket) {
|
||||||
for {
|
for {
|
||||||
msgs, err := nlSock.Recieve()
|
msgs, err := nlSock.Receive()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Failed to receive from netlink: %v ", err)
|
logrus.Errorf("Failed to receive from netlink: %v ", err)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -54,6 +54,7 @@ func createVxlan(vni uint32) (string, error) {
|
||||||
LinkAttrs: netlink.LinkAttrs{Name: name},
|
LinkAttrs: netlink.LinkAttrs{Name: name},
|
||||||
VxlanId: int(vni),
|
VxlanId: int(vni),
|
||||||
Learning: true,
|
Learning: true,
|
||||||
|
Port: vxlanPort,
|
||||||
Proxy: true,
|
Proxy: true,
|
||||||
L3miss: true,
|
L3miss: true,
|
||||||
L2miss: true,
|
L2miss: true,
|
||||||
|
|
|
@ -21,6 +21,7 @@ const (
|
||||||
vethLen = 7
|
vethLen = 7
|
||||||
vxlanIDStart = 256
|
vxlanIDStart = 256
|
||||||
vxlanIDEnd = 1000
|
vxlanIDEnd = 1000
|
||||||
|
vxlanPort = 4789
|
||||||
)
|
)
|
||||||
|
|
||||||
type driver struct {
|
type driver struct {
|
||||||
|
|
|
@ -811,9 +811,19 @@ func (ep *endpoint) updateDNS(resolvConf []byte) error {
|
||||||
return os.Rename(tmpResolvFile.Name(), container.config.resolvConfPath)
|
return os.Rename(tmpResolvFile.Name(), container.config.resolvConfPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func copyFile(src, dst string) error {
|
||||||
|
sBytes, err := ioutil.ReadFile(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioutil.WriteFile(dst, sBytes, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
func (ep *endpoint) setupDNS() error {
|
func (ep *endpoint) setupDNS() error {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
container := ep.container
|
container := ep.container
|
||||||
|
joinInfo := ep.joinInfo
|
||||||
ep.Unlock()
|
ep.Unlock()
|
||||||
|
|
||||||
if container == nil {
|
if container == nil {
|
||||||
|
@ -830,6 +840,14 @@ func (ep *endpoint) setupDNS() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if joinInfo.resolvConfPath != "" {
|
||||||
|
if err := copyFile(joinInfo.resolvConfPath, container.config.resolvConfPath); err != nil {
|
||||||
|
return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", joinInfo.resolvConfPath, container.config.resolvConfPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
resolvConf, err := resolvconf.Get()
|
resolvConf, err := resolvconf.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -43,13 +43,19 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
mybridge := &netlink.Bridge{netlink.LinkAttrs{Name: "foo"}}
|
la := netlink.NewLinkAttrs()
|
||||||
|
la.Name = "foo"
|
||||||
|
mybridge := &netlink.Bridge{la}}
|
||||||
_ := netlink.LinkAdd(mybridge)
|
_ := netlink.LinkAdd(mybridge)
|
||||||
eth1, _ := netlink.LinkByName("eth1")
|
eth1, _ := netlink.LinkByName("eth1")
|
||||||
netlink.LinkSetMaster(eth1, mybridge)
|
netlink.LinkSetMaster(eth1, mybridge)
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
Note `NewLinkAttrs` constructor, it sets default values in structure. For now
|
||||||
|
it sets only `TxQLen` to `-1`, so kernel will set default by itself. If you're
|
||||||
|
using simple initialization(`LinkAttrs{Name: "foo"}`) `TxQLen` will be set to
|
||||||
|
`0` unless you specify it like `LinkAttrs{Name: "foo", TxQLen: 1000}`.
|
||||||
|
|
||||||
Add a new ip address to loopback:
|
Add a new ip address to loopback:
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@ type Addr struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns $ip/$netmask $label
|
// String returns $ip/$netmask $label
|
||||||
func (addr Addr) String() string {
|
func (a Addr) String() string {
|
||||||
return fmt.Sprintf("%s %s", addr.IPNet, addr.Label)
|
return fmt.Sprintf("%s %s", a.IPNet, a.Label)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseAddr parses the string representation of an address in the
|
// ParseAddr parses the string representation of an address in the
|
||||||
|
|
|
@ -81,7 +81,7 @@ func AddrList(link Link, family int) ([]Addr, error) {
|
||||||
index = base.Index
|
index = base.Index
|
||||||
}
|
}
|
||||||
|
|
||||||
res := make([]Addr, 0)
|
var res []Addr
|
||||||
for _, m := range msgs {
|
for _, m := range msgs {
|
||||||
msg := nl.DeserializeIfAddrmsg(m)
|
msg := nl.DeserializeIfAddrmsg(m)
|
||||||
|
|
||||||
|
@ -95,11 +95,17 @@ func AddrList(link Link, family int) ([]Addr, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var local, dst *net.IPNet
|
||||||
var addr Addr
|
var addr Addr
|
||||||
for _, attr := range attrs {
|
for _, attr := range attrs {
|
||||||
switch attr.Attr.Type {
|
switch attr.Attr.Type {
|
||||||
case syscall.IFA_ADDRESS:
|
case syscall.IFA_ADDRESS:
|
||||||
addr.IPNet = &net.IPNet{
|
dst = &net.IPNet{
|
||||||
|
IP: attr.Value,
|
||||||
|
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
|
||||||
|
}
|
||||||
|
case syscall.IFA_LOCAL:
|
||||||
|
local = &net.IPNet{
|
||||||
IP: attr.Value,
|
IP: attr.Value,
|
||||||
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
|
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
|
||||||
}
|
}
|
||||||
|
@ -107,6 +113,14 @@ func AddrList(link Link, family int) ([]Addr, error) {
|
||||||
addr.Label = string(attr.Value[:len(attr.Value)-1])
|
addr.Label = string(attr.Value[:len(attr.Value)-1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
|
||||||
|
if local != nil {
|
||||||
|
addr.IPNet = local
|
||||||
|
} else {
|
||||||
|
addr.IPNet = dst
|
||||||
|
}
|
||||||
|
|
||||||
res = append(res, addr)
|
res = append(res, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,16 +10,29 @@ type Link interface {
|
||||||
Type() string
|
Type() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
NsPid int
|
||||||
|
NsFd int
|
||||||
|
)
|
||||||
|
|
||||||
// LinkAttrs represents data shared by most link types
|
// LinkAttrs represents data shared by most link types
|
||||||
type LinkAttrs struct {
|
type LinkAttrs struct {
|
||||||
Index int
|
Index int
|
||||||
MTU int
|
MTU int
|
||||||
TxQLen uint32 // Transmit Queue Length
|
TxQLen int // Transmit Queue Length
|
||||||
Name string
|
Name string
|
||||||
HardwareAddr net.HardwareAddr
|
HardwareAddr net.HardwareAddr
|
||||||
Flags net.Flags
|
Flags net.Flags
|
||||||
ParentIndex int // index of the parent link device
|
ParentIndex int // index of the parent link device
|
||||||
MasterIndex int // must be the index of a bridge
|
MasterIndex int // must be the index of a bridge
|
||||||
|
Namespace interface{} // nil | NsPid | NsFd
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLinkAttrs returns LinkAttrs structure filled with default values
|
||||||
|
func NewLinkAttrs() LinkAttrs {
|
||||||
|
return LinkAttrs{
|
||||||
|
TxQLen: -1,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Device links cannot be created via netlink. These links
|
// Device links cannot be created via netlink. These links
|
||||||
|
@ -76,9 +89,21 @@ func (vlan *Vlan) Type() string {
|
||||||
return "vlan"
|
return "vlan"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MacvlanMode uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
MACVLAN_MODE_DEFAULT MacvlanMode = iota
|
||||||
|
MACVLAN_MODE_PRIVATE
|
||||||
|
MACVLAN_MODE_VEPA
|
||||||
|
MACVLAN_MODE_BRIDGE
|
||||||
|
MACVLAN_MODE_PASSTHRU
|
||||||
|
MACVLAN_MODE_SOURCE
|
||||||
|
)
|
||||||
|
|
||||||
// Macvlan links have ParentIndex set in their Attrs()
|
// Macvlan links have ParentIndex set in their Attrs()
|
||||||
type Macvlan struct {
|
type Macvlan struct {
|
||||||
LinkAttrs
|
LinkAttrs
|
||||||
|
Mode MacvlanMode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (macvlan *Macvlan) Attrs() *LinkAttrs {
|
func (macvlan *Macvlan) Attrs() *LinkAttrs {
|
||||||
|
|
|
@ -13,6 +13,15 @@ import (
|
||||||
var native = nl.NativeEndian()
|
var native = nl.NativeEndian()
|
||||||
var lookupByDump = false
|
var lookupByDump = false
|
||||||
|
|
||||||
|
var macvlanModes = [...]uint32{
|
||||||
|
0,
|
||||||
|
nl.MACVLAN_MODE_PRIVATE,
|
||||||
|
nl.MACVLAN_MODE_VEPA,
|
||||||
|
nl.MACVLAN_MODE_BRIDGE,
|
||||||
|
nl.MACVLAN_MODE_PASSTHRU,
|
||||||
|
nl.MACVLAN_MODE_SOURCE,
|
||||||
|
}
|
||||||
|
|
||||||
func ensureIndex(link *LinkAttrs) {
|
func ensureIndex(link *LinkAttrs) {
|
||||||
if link != nil && link.Index == 0 {
|
if link != nil && link.Index == 0 {
|
||||||
newlink, _ := LinkByName(link.Name)
|
newlink, _ := LinkByName(link.Name)
|
||||||
|
@ -39,7 +48,7 @@ func LinkSetUp(link Link) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// LinkSetUp disables link device.
|
// LinkSetDown disables link device.
|
||||||
// Equivalent to: `ip link set $link down`
|
// Equivalent to: `ip link set $link down`
|
||||||
func LinkSetDown(link Link) error {
|
func LinkSetDown(link Link) error {
|
||||||
base := link.Attrs()
|
base := link.Attrs()
|
||||||
|
@ -67,7 +76,7 @@ func LinkSetMTU(link Link, mtu int) error {
|
||||||
msg.Type = syscall.RTM_SETLINK
|
msg.Type = syscall.RTM_SETLINK
|
||||||
msg.Flags = syscall.NLM_F_REQUEST
|
msg.Flags = syscall.NLM_F_REQUEST
|
||||||
msg.Index = int32(base.Index)
|
msg.Index = int32(base.Index)
|
||||||
msg.Change = nl.DEFAULT_CHANGE
|
msg.Change = syscall.IFLA_MTU
|
||||||
req.AddData(msg)
|
req.AddData(msg)
|
||||||
|
|
||||||
b := make([]byte, 4)
|
b := make([]byte, 4)
|
||||||
|
@ -91,7 +100,7 @@ func LinkSetName(link Link, name string) error {
|
||||||
msg.Type = syscall.RTM_SETLINK
|
msg.Type = syscall.RTM_SETLINK
|
||||||
msg.Flags = syscall.NLM_F_REQUEST
|
msg.Flags = syscall.NLM_F_REQUEST
|
||||||
msg.Index = int32(base.Index)
|
msg.Index = int32(base.Index)
|
||||||
msg.Change = nl.DEFAULT_CHANGE
|
msg.Change = syscall.IFLA_IFNAME
|
||||||
req.AddData(msg)
|
req.AddData(msg)
|
||||||
|
|
||||||
data := nl.NewRtAttr(syscall.IFLA_IFNAME, []byte(name))
|
data := nl.NewRtAttr(syscall.IFLA_IFNAME, []byte(name))
|
||||||
|
@ -112,7 +121,7 @@ func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
|
||||||
msg.Type = syscall.RTM_SETLINK
|
msg.Type = syscall.RTM_SETLINK
|
||||||
msg.Flags = syscall.NLM_F_REQUEST
|
msg.Flags = syscall.NLM_F_REQUEST
|
||||||
msg.Index = int32(base.Index)
|
msg.Index = int32(base.Index)
|
||||||
msg.Change = nl.DEFAULT_CHANGE
|
msg.Change = syscall.IFLA_ADDRESS
|
||||||
req.AddData(msg)
|
req.AddData(msg)
|
||||||
|
|
||||||
data := nl.NewRtAttr(syscall.IFLA_ADDRESS, []byte(hwaddr))
|
data := nl.NewRtAttr(syscall.IFLA_ADDRESS, []byte(hwaddr))
|
||||||
|
@ -145,7 +154,7 @@ func LinkSetMasterByIndex(link Link, masterIndex int) error {
|
||||||
msg.Type = syscall.RTM_SETLINK
|
msg.Type = syscall.RTM_SETLINK
|
||||||
msg.Flags = syscall.NLM_F_REQUEST
|
msg.Flags = syscall.NLM_F_REQUEST
|
||||||
msg.Index = int32(base.Index)
|
msg.Index = int32(base.Index)
|
||||||
msg.Change = nl.DEFAULT_CHANGE
|
msg.Change = syscall.IFLA_MASTER
|
||||||
req.AddData(msg)
|
req.AddData(msg)
|
||||||
|
|
||||||
b := make([]byte, 4)
|
b := make([]byte, 4)
|
||||||
|
@ -170,7 +179,7 @@ func LinkSetNsPid(link Link, nspid int) error {
|
||||||
msg.Type = syscall.RTM_SETLINK
|
msg.Type = syscall.RTM_SETLINK
|
||||||
msg.Flags = syscall.NLM_F_REQUEST
|
msg.Flags = syscall.NLM_F_REQUEST
|
||||||
msg.Index = int32(base.Index)
|
msg.Index = int32(base.Index)
|
||||||
msg.Change = nl.DEFAULT_CHANGE
|
msg.Change = syscall.IFLA_NET_NS_PID
|
||||||
req.AddData(msg)
|
req.AddData(msg)
|
||||||
|
|
||||||
b := make([]byte, 4)
|
b := make([]byte, 4)
|
||||||
|
@ -183,7 +192,7 @@ func LinkSetNsPid(link Link, nspid int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// LinkSetNsPid puts the device into a new network namespace. The
|
// LinkSetNsFd puts the device into a new network namespace. The
|
||||||
// fd must be an open file descriptor to a network namespace.
|
// fd must be an open file descriptor to a network namespace.
|
||||||
// Similar to: `ip link set $link netns $ns`
|
// Similar to: `ip link set $link netns $ns`
|
||||||
func LinkSetNsFd(link Link, fd int) error {
|
func LinkSetNsFd(link Link, fd int) error {
|
||||||
|
@ -195,7 +204,7 @@ func LinkSetNsFd(link Link, fd int) error {
|
||||||
msg.Type = syscall.RTM_SETLINK
|
msg.Type = syscall.RTM_SETLINK
|
||||||
msg.Flags = syscall.NLM_F_REQUEST
|
msg.Flags = syscall.NLM_F_REQUEST
|
||||||
msg.Index = int32(base.Index)
|
msg.Index = int32(base.Index)
|
||||||
msg.Change = nl.DEFAULT_CHANGE
|
msg.Change = nl.IFLA_NET_NS_FD
|
||||||
req.AddData(msg)
|
req.AddData(msg)
|
||||||
|
|
||||||
b := make([]byte, 4)
|
b := make([]byte, 4)
|
||||||
|
@ -312,11 +321,28 @@ func LinkAdd(link Link) error {
|
||||||
req.AddData(mtu)
|
req.AddData(mtu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if base.TxQLen >= 0 {
|
||||||
|
qlen := nl.NewRtAttr(syscall.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
|
||||||
|
req.AddData(qlen)
|
||||||
|
}
|
||||||
|
|
||||||
|
if base.Namespace != nil {
|
||||||
|
var attr *nl.RtAttr
|
||||||
|
switch base.Namespace.(type) {
|
||||||
|
case NsPid:
|
||||||
|
val := nl.Uint32Attr(uint32(base.Namespace.(NsPid)))
|
||||||
|
attr = nl.NewRtAttr(syscall.IFLA_NET_NS_PID, val)
|
||||||
|
case NsFd:
|
||||||
|
val := nl.Uint32Attr(uint32(base.Namespace.(NsFd)))
|
||||||
|
attr = nl.NewRtAttr(nl.IFLA_NET_NS_FD, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.AddData(attr)
|
||||||
|
}
|
||||||
|
|
||||||
linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil)
|
linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil)
|
||||||
nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
|
nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
|
||||||
|
|
||||||
nl.NewRtAttrChild(linkInfo, syscall.IFLA_TXQLEN, nl.Uint32Attr(base.TxQLen))
|
|
||||||
|
|
||||||
if vlan, ok := link.(*Vlan); ok {
|
if vlan, ok := link.(*Vlan); ok {
|
||||||
b := make([]byte, 2)
|
b := make([]byte, 2)
|
||||||
native.PutUint16(b, uint16(vlan.VlanId))
|
native.PutUint16(b, uint16(vlan.VlanId))
|
||||||
|
@ -327,15 +353,23 @@ func LinkAdd(link Link) error {
|
||||||
peer := nl.NewRtAttrChild(data, nl.VETH_INFO_PEER, nil)
|
peer := nl.NewRtAttrChild(data, nl.VETH_INFO_PEER, nil)
|
||||||
nl.NewIfInfomsgChild(peer, syscall.AF_UNSPEC)
|
nl.NewIfInfomsgChild(peer, syscall.AF_UNSPEC)
|
||||||
nl.NewRtAttrChild(peer, syscall.IFLA_IFNAME, nl.ZeroTerminated(veth.PeerName))
|
nl.NewRtAttrChild(peer, syscall.IFLA_IFNAME, nl.ZeroTerminated(veth.PeerName))
|
||||||
nl.NewRtAttrChild(peer, syscall.IFLA_TXQLEN, nl.Uint32Attr(base.TxQLen))
|
if base.TxQLen >= 0 {
|
||||||
|
nl.NewRtAttrChild(peer, syscall.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
|
||||||
|
}
|
||||||
if base.MTU > 0 {
|
if base.MTU > 0 {
|
||||||
nl.NewRtAttrChild(peer, syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
|
nl.NewRtAttrChild(peer, syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if vxlan, ok := link.(*Vxlan); ok {
|
} else if vxlan, ok := link.(*Vxlan); ok {
|
||||||
addVxlanAttrs(vxlan, linkInfo)
|
addVxlanAttrs(vxlan, linkInfo)
|
||||||
} else if ipv, ok := link.(*IPVlan); ok {
|
} else if ipv, ok := link.(*IPVlan); ok {
|
||||||
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
|
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
|
||||||
nl.NewRtAttrChild(data, nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(ipv.Mode)))
|
nl.NewRtAttrChild(data, nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(ipv.Mode)))
|
||||||
|
} else if macv, ok := link.(*Macvlan); ok {
|
||||||
|
if macv.Mode != MACVLAN_MODE_DEFAULT {
|
||||||
|
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
|
||||||
|
nl.NewRtAttrChild(data, nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[macv.Mode]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
req.AddData(linkInfo)
|
req.AddData(linkInfo)
|
||||||
|
@ -483,6 +517,8 @@ func linkDeserialize(m []byte) (Link, error) {
|
||||||
link = &Vxlan{}
|
link = &Vxlan{}
|
||||||
case "ipvlan":
|
case "ipvlan":
|
||||||
link = &IPVlan{}
|
link = &IPVlan{}
|
||||||
|
case "macvlan":
|
||||||
|
link = &Macvlan{}
|
||||||
default:
|
default:
|
||||||
link = &Generic{LinkType: linkType}
|
link = &Generic{LinkType: linkType}
|
||||||
}
|
}
|
||||||
|
@ -498,6 +534,8 @@ func linkDeserialize(m []byte) (Link, error) {
|
||||||
parseVxlanData(link, data)
|
parseVxlanData(link, data)
|
||||||
case "ipvlan":
|
case "ipvlan":
|
||||||
parseIPVlanData(link, data)
|
parseIPVlanData(link, data)
|
||||||
|
case "macvlan":
|
||||||
|
parseMacvlanData(link, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -520,7 +558,7 @@ func linkDeserialize(m []byte) (Link, error) {
|
||||||
case syscall.IFLA_MASTER:
|
case syscall.IFLA_MASTER:
|
||||||
base.MasterIndex = int(native.Uint32(attr.Value[0:4]))
|
base.MasterIndex = int(native.Uint32(attr.Value[0:4]))
|
||||||
case syscall.IFLA_TXQLEN:
|
case syscall.IFLA_TXQLEN:
|
||||||
base.TxQLen = native.Uint32(attr.Value[0:4])
|
base.TxQLen = int(native.Uint32(attr.Value[0:4]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Links that don't have IFLA_INFO_KIND are hardware devices
|
// Links that don't have IFLA_INFO_KIND are hardware devices
|
||||||
|
@ -547,8 +585,7 @@ func LinkList() ([]Link, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res := make([]Link, 0)
|
var res []Link
|
||||||
|
|
||||||
for _, m := range msgs {
|
for _, m := range msgs {
|
||||||
link, err := linkDeserialize(m)
|
link, err := linkDeserialize(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -593,7 +630,7 @@ func setProtinfoAttr(link Link, mode bool, attr int) error {
|
||||||
msg.Type = syscall.RTM_SETLINK
|
msg.Type = syscall.RTM_SETLINK
|
||||||
msg.Flags = syscall.NLM_F_REQUEST
|
msg.Flags = syscall.NLM_F_REQUEST
|
||||||
msg.Index = int32(base.Index)
|
msg.Index = int32(base.Index)
|
||||||
msg.Change = nl.DEFAULT_CHANGE
|
msg.Change = syscall.IFLA_PROTINFO | syscall.NLA_F_NESTED
|
||||||
req.AddData(msg)
|
req.AddData(msg)
|
||||||
|
|
||||||
br := nl.NewRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil)
|
br := nl.NewRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil)
|
||||||
|
@ -674,6 +711,27 @@ func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseMacvlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||||
|
macv := link.(*Macvlan)
|
||||||
|
for _, datum := range data {
|
||||||
|
if datum.Attr.Type == nl.IFLA_MACVLAN_MODE {
|
||||||
|
switch native.Uint32(datum.Value[0:4]) {
|
||||||
|
case nl.MACVLAN_MODE_PRIVATE:
|
||||||
|
macv.Mode = MACVLAN_MODE_PRIVATE
|
||||||
|
case nl.MACVLAN_MODE_VEPA:
|
||||||
|
macv.Mode = MACVLAN_MODE_VEPA
|
||||||
|
case nl.MACVLAN_MODE_BRIDGE:
|
||||||
|
macv.Mode = MACVLAN_MODE_BRIDGE
|
||||||
|
case nl.MACVLAN_MODE_PASSTHRU:
|
||||||
|
macv.Mode = MACVLAN_MODE_PASSTHRU
|
||||||
|
case nl.MACVLAN_MODE_SOURCE:
|
||||||
|
macv.Mode = MACVLAN_MODE_SOURCE
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// copied from pkg/net_linux.go
|
// copied from pkg/net_linux.go
|
||||||
func linkFlags(rawFlags uint32) net.Flags {
|
func linkFlags(rawFlags uint32) net.Flags {
|
||||||
var f net.Flags
|
var f net.Flags
|
||||||
|
|
|
@ -141,7 +141,7 @@ func NeighList(linkIndex, family int) ([]Neigh, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res := make([]Neigh, 0)
|
var res []Neigh
|
||||||
for _, m := range msgs {
|
for _, m := range msgs {
|
||||||
ndm := deserializeNdmsg(m)
|
ndm := deserializeNdmsg(m)
|
||||||
if linkIndex != 0 && int(ndm.Index) != linkIndex {
|
if linkIndex != 0 && int(ndm.Index) != linkIndex {
|
||||||
|
|
|
@ -79,3 +79,18 @@ const (
|
||||||
// not defined in syscall
|
// not defined in syscall
|
||||||
IFLA_NET_NS_FD = 28
|
IFLA_NET_NS_FD = 28
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
IFLA_MACVLAN_UNSPEC = iota
|
||||||
|
IFLA_MACVLAN_MODE
|
||||||
|
IFLA_MACVLAN_FLAGS
|
||||||
|
IFLA_MACVLAN_MAX = IFLA_MACVLAN_FLAGS
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MACVLAN_MODE_PRIVATE = 1
|
||||||
|
MACVLAN_MODE_VEPA = 2
|
||||||
|
MACVLAN_MODE_BRIDGE = 4
|
||||||
|
MACVLAN_MODE_PASSTHRU = 8
|
||||||
|
MACVLAN_MODE_SOURCE = 16
|
||||||
|
)
|
||||||
|
|
|
@ -172,16 +172,16 @@ type NetlinkRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize the Netlink Request into a byte array
|
// Serialize the Netlink Request into a byte array
|
||||||
func (msg *NetlinkRequest) Serialize() []byte {
|
func (req *NetlinkRequest) Serialize() []byte {
|
||||||
length := syscall.SizeofNlMsghdr
|
length := syscall.SizeofNlMsghdr
|
||||||
dataBytes := make([][]byte, len(msg.Data))
|
dataBytes := make([][]byte, len(req.Data))
|
||||||
for i, data := range msg.Data {
|
for i, data := range req.Data {
|
||||||
dataBytes[i] = data.Serialize()
|
dataBytes[i] = data.Serialize()
|
||||||
length = length + len(dataBytes[i])
|
length = length + len(dataBytes[i])
|
||||||
}
|
}
|
||||||
msg.Len = uint32(length)
|
req.Len = uint32(length)
|
||||||
b := make([]byte, length)
|
b := make([]byte, length)
|
||||||
hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(msg)))[:]
|
hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:]
|
||||||
next := syscall.SizeofNlMsghdr
|
next := syscall.SizeofNlMsghdr
|
||||||
copy(b[0:next], hdr)
|
copy(b[0:next], hdr)
|
||||||
for _, data := range dataBytes {
|
for _, data := range dataBytes {
|
||||||
|
@ -193,9 +193,9 @@ func (msg *NetlinkRequest) Serialize() []byte {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *NetlinkRequest) AddData(data NetlinkRequestData) {
|
func (req *NetlinkRequest) AddData(data NetlinkRequestData) {
|
||||||
if data != nil {
|
if data != nil {
|
||||||
msg.Data = append(msg.Data, data)
|
req.Data = append(req.Data, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,11 +218,11 @@ func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, erro
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res := make([][]byte, 0)
|
var res [][]byte
|
||||||
|
|
||||||
done:
|
done:
|
||||||
for {
|
for {
|
||||||
msgs, err := s.Recieve()
|
msgs, err := s.Receive()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -294,7 +294,7 @@ func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
|
||||||
|
|
||||||
// Create a netlink socket with a given protocol (e.g. NETLINK_ROUTE)
|
// Create a netlink socket with a given protocol (e.g. NETLINK_ROUTE)
|
||||||
// and subscribe it to multicast groups passed in variable argument list.
|
// and subscribe it to multicast groups passed in variable argument list.
|
||||||
// Returns the netlink socket on whic hReceive() method can be called
|
// Returns the netlink socket on which Receive() method can be called
|
||||||
// to retrieve the messages from the kernel.
|
// to retrieve the messages from the kernel.
|
||||||
func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
|
func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
|
||||||
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol)
|
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol)
|
||||||
|
@ -329,7 +329,7 @@ func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NetlinkSocket) Recieve() ([]syscall.NetlinkMessage, error) {
|
func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
|
||||||
rb := make([]byte, syscall.Getpagesize())
|
rb := make([]byte, syscall.Getpagesize())
|
||||||
nr, _, err := syscall.Recvfrom(s.fd, rb, 0)
|
nr, _, err := syscall.Recvfrom(s.fd, rb, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -104,9 +104,8 @@ func (x *XfrmAddress) ToIPNet(prefixlen uint8) *net.IPNet {
|
||||||
ip := x.ToIP()
|
ip := x.ToIP()
|
||||||
if GetIPFamily(ip) == FAMILY_V4 {
|
if GetIPFamily(ip) == FAMILY_V4 {
|
||||||
return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 32)}
|
return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 32)}
|
||||||
} else {
|
|
||||||
return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 128)}
|
|
||||||
}
|
}
|
||||||
|
return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 128)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *XfrmAddress) FromIP(ip net.IP) {
|
func (x *XfrmAddress) FromIP(ip net.IP) {
|
||||||
|
@ -125,8 +124,8 @@ func DeserializeXfrmAddress(b []byte) *XfrmAddress {
|
||||||
return (*XfrmAddress)(unsafe.Pointer(&b[0:SizeofXfrmAddress][0]))
|
return (*XfrmAddress)(unsafe.Pointer(&b[0:SizeofXfrmAddress][0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *XfrmAddress) Serialize() []byte {
|
func (x *XfrmAddress) Serialize() []byte {
|
||||||
return (*(*[SizeofXfrmAddress]byte)(unsafe.Pointer(msg)))[:]
|
return (*(*[SizeofXfrmAddress]byte)(unsafe.Pointer(x)))[:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// struct xfrm_selector {
|
// struct xfrm_selector {
|
||||||
|
|
|
@ -16,7 +16,7 @@ type Protinfo struct {
|
||||||
|
|
||||||
// String returns a list of enabled flags
|
// String returns a list of enabled flags
|
||||||
func (prot *Protinfo) String() string {
|
func (prot *Protinfo) String() string {
|
||||||
boolStrings := make([]string, 0)
|
var boolStrings []string
|
||||||
if prot.Hairpin {
|
if prot.Hairpin {
|
||||||
boolStrings = append(boolStrings, "Hairpin")
|
boolStrings = append(boolStrings, "Hairpin")
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ func RouteList(link Link, family int) ([]Route, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
native := nl.NativeEndian()
|
native := nl.NativeEndian()
|
||||||
res := make([]Route, 0)
|
var res []Route
|
||||||
for _, m := range msgs {
|
for _, m := range msgs {
|
||||||
msg := nl.DeserializeRtMsg(m)
|
msg := nl.DeserializeRtMsg(m)
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ func RouteGet(destination net.IP) ([]Route, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
native := nl.NativeEndian()
|
native := nl.NativeEndian()
|
||||||
res := make([]Route, 0)
|
var res []Route
|
||||||
for _, m := range msgs {
|
for _, m := range msgs {
|
||||||
msg := nl.DeserializeRtMsg(m)
|
msg := nl.DeserializeRtMsg(m)
|
||||||
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
|
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
|
||||||
|
|
|
@ -84,7 +84,7 @@ func XfrmPolicyList(family int) ([]XfrmPolicy, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res := make([]XfrmPolicy, 0)
|
var res []XfrmPolicy
|
||||||
for _, m := range msgs {
|
for _, m := range msgs {
|
||||||
msg := nl.DeserializeXfrmUserpolicyInfo(m)
|
msg := nl.DeserializeXfrmUserpolicyInfo(m)
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ func XfrmStateList(family int) ([]XfrmState, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res := make([]XfrmState, 0)
|
var res []XfrmState
|
||||||
for _, m := range msgs {
|
for _, m := range msgs {
|
||||||
msg := nl.DeserializeXfrmUsersaInfo(m)
|
msg := nl.DeserializeXfrmUsersaInfo(m)
|
||||||
|
|
||||||
|
|
|
@ -52,33 +52,30 @@ func Get() (NsHandle, error) {
|
||||||
return GetFromThread(os.Getpid(), syscall.Gettid())
|
return GetFromThread(os.Getpid(), syscall.Gettid())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFromName gets a handle to a named network namespace such as one
|
// GetFromPath gets a handle to a network namespace
|
||||||
// created by `ip netns add`.
|
// identified by the path
|
||||||
func GetFromName(name string) (NsHandle, error) {
|
func GetFromPath(path string) (NsHandle, error) {
|
||||||
fd, err := syscall.Open(fmt.Sprintf("/var/run/netns/%s", name), syscall.O_RDONLY, 0)
|
fd, err := syscall.Open(path, syscall.O_RDONLY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
return NsHandle(fd), nil
|
return NsHandle(fd), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFromName gets a handle to a named network namespace such as one
|
||||||
|
// created by `ip netns add`.
|
||||||
|
func GetFromName(name string) (NsHandle, error) {
|
||||||
|
return GetFromPath(fmt.Sprintf("/var/run/netns/%s", name))
|
||||||
|
}
|
||||||
|
|
||||||
// GetFromPid gets a handle to the network namespace of a given pid.
|
// GetFromPid gets a handle to the network namespace of a given pid.
|
||||||
func GetFromPid(pid int) (NsHandle, error) {
|
func GetFromPid(pid int) (NsHandle, error) {
|
||||||
fd, err := syscall.Open(fmt.Sprintf("/proc/%d/ns/net", pid), syscall.O_RDONLY, 0)
|
return GetFromPath(fmt.Sprintf("/proc/%d/ns/net", pid))
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
return NsHandle(fd), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFromThread gets a handle to the network namespace of a given pid and tid.
|
// GetFromThread gets a handle to the network namespace of a given pid and tid.
|
||||||
func GetFromThread(pid, tid int) (NsHandle, error) {
|
func GetFromThread(pid, tid int) (NsHandle, error) {
|
||||||
name := fmt.Sprintf("/proc/%d/task/%d/ns/net", pid, tid)
|
return GetFromPath(fmt.Sprintf("/proc/%d/task/%d/ns/net", pid, tid))
|
||||||
fd, err := syscall.Open(name, syscall.O_RDONLY, 0)
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
return NsHandle(fd), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFromDocker gets a handle to the network namespace of a docker container.
|
// GetFromDocker gets a handle to the network namespace of a docker container.
|
||||||
|
|
|
@ -3,5 +3,5 @@
|
||||||
package netns
|
package netns
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SYS_SETNS = 374
|
SYS_SETNS = 375
|
||||||
)
|
)
|
||||||
|
|
7
vendor/src/github.com/vishvananda/netns/netns_linux_arm64.go
vendored
Normal file
7
vendor/src/github.com/vishvananda/netns/netns_linux_arm64.go
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// +build linux,arm64
|
||||||
|
|
||||||
|
package netns
|
||||||
|
|
||||||
|
const (
|
||||||
|
SYS_SETNS = 268
|
||||||
|
)
|
Loading…
Reference in a new issue