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>
| ... | ... |
@@ -18,14 +18,14 @@ clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://gith |
| 18 | 18 |
clone hg code.google.com/p/gosqlite 74691fb6f837 |
| 19 | 19 |
|
| 20 | 20 |
#get libnetwork packages |
| 21 |
-clone git github.com/docker/libnetwork 4c14cd316f40f16bc1c17e420b18a1902dc575a7 |
|
| 21 |
+clone git github.com/docker/libnetwork 0517ceae7dea82ded435b99af810efa27b56de73 |
|
| 22 | 22 |
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec |
| 23 | 23 |
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b |
| 24 | 24 |
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4 |
| 25 | 25 |
clone git github.com/hashicorp/serf 7151adcef72687bf95f451a2e0ba15cb19412bf2 |
| 26 |
-clone git github.com/docker/libkv e8cde779d58273d240c1eff065352a6cd67027dd |
|
| 27 |
-clone git github.com/vishvananda/netns 5478c060110032f972e86a1f844fdb9a2f008f2c |
|
| 28 |
-clone git github.com/vishvananda/netlink 8eb64238879fed52fd51c5b30ad20b928fb4c36c |
|
| 26 |
+clone git github.com/docker/libkv 60c7c881345b3c67defc7f93a8297debf041d43c |
|
| 27 |
+clone git github.com/vishvananda/netns 493029407eeb434d0c2d44e02ea072ff2488d322 |
|
| 28 |
+clone git github.com/vishvananda/netlink 20397a138846e4d6590e01783ed023ed7e1c38a6 |
|
| 29 | 29 |
clone git github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060 |
| 30 | 30 |
clone git github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374 |
| 31 | 31 |
clone git github.com/coreos/go-etcd v2.0.0 |
| ... | ... |
@@ -11,8 +11,8 @@ sudo: false |
| 11 | 11 |
before_install: |
| 12 | 12 |
# Symlink below is needed for Travis CI to work correctly on personal forks of libkv |
| 13 | 13 |
- ln -s $HOME/gopath/src/github.com/${TRAVIS_REPO_SLUG///libkv/} $HOME/gopath/src/github.com/docker
|
| 14 |
- - go get code.google.com/p/go.tools/cmd/vet |
|
| 15 |
- - go get code.google.com/p/go.tools/cmd/cover |
|
| 14 |
+ - go get golang.org/x/tools/cmd/vet |
|
| 15 |
+ - go get golang.org/x/tools/cmd/cover |
|
| 16 | 16 |
- go get github.com/mattn/goveralls |
| 17 | 17 |
- go get github.com/golang/lint/golint |
| 18 | 18 |
- go get github.com/GeertJohan/fgt |
| ... | ... |
@@ -99,8 +99,9 @@ func (s *Consul) refreshSession(pair *api.KVPair) error {
|
| 99 | 99 |
|
| 100 | 100 |
if session == "" {
|
| 101 | 101 |
entry := &api.SessionEntry{
|
| 102 |
- Behavior: api.SessionBehaviorDelete, |
|
| 103 |
- TTL: s.ephemeralTTL.String(), |
|
| 102 |
+ Behavior: api.SessionBehaviorDelete, // Delete the key when the session expires |
|
| 103 |
+ TTL: ((s.ephemeralTTL) / 2).String(), // Consul multiplies the TTL by 2x |
|
| 104 |
+ LockDelay: 1 * time.Millisecond, // Virtually disable lock delay |
|
| 104 | 105 |
} |
| 105 | 106 |
|
| 106 | 107 |
// Create the key session |
| ... | ... |
@@ -108,19 +109,19 @@ func (s *Consul) refreshSession(pair *api.KVPair) error {
|
| 108 | 108 |
if err != nil {
|
| 109 | 109 |
return err |
| 110 | 110 |
} |
| 111 |
- } |
|
| 112 | 111 |
|
| 113 |
- lockOpts := &api.LockOptions{
|
|
| 114 |
- Key: pair.Key, |
|
| 115 |
- Session: session, |
|
| 116 |
- } |
|
| 112 |
+ lockOpts := &api.LockOptions{
|
|
| 113 |
+ Key: pair.Key, |
|
| 114 |
+ Session: session, |
|
| 115 |
+ } |
|
| 117 | 116 |
|
| 118 |
- // Lock and ignore if lock is held |
|
| 119 |
- // It's just a placeholder for the |
|
| 120 |
- // ephemeral behavior |
|
| 121 |
- lock, _ := s.client.LockOpts(lockOpts) |
|
| 122 |
- if lock != nil {
|
|
| 123 |
- lock.Lock(nil) |
|
| 117 |
+ // Lock and ignore if lock is held |
|
| 118 |
+ // It's just a placeholder for the |
|
| 119 |
+ // ephemeral behavior |
|
| 120 |
+ lock, _ := s.client.LockOpts(lockOpts) |
|
| 121 |
+ if lock != nil {
|
|
| 122 |
+ lock.Lock(nil) |
|
| 123 |
+ } |
|
| 124 | 124 |
} |
| 125 | 125 |
|
| 126 | 126 |
_, _, err = s.client.Session().Renew(session, nil) |
| ... | ... |
@@ -321,18 +322,18 @@ func (s *Consul) WatchTree(directory string, stopCh <-chan struct{}) (<-chan []*
|
| 321 | 321 |
opts.WaitIndex = meta.LastIndex |
| 322 | 322 |
|
| 323 | 323 |
// Return children KV pairs to the channel |
| 324 |
- kv := []*store.KVPair{}
|
|
| 324 |
+ kvpairs := []*store.KVPair{}
|
|
| 325 | 325 |
for _, pair := range pairs {
|
| 326 | 326 |
if pair.Key == directory {
|
| 327 | 327 |
continue |
| 328 | 328 |
} |
| 329 |
- kv = append(kv, &store.KVPair{
|
|
| 329 |
+ kvpairs = append(kvpairs, &store.KVPair{
|
|
| 330 | 330 |
Key: pair.Key, |
| 331 | 331 |
Value: pair.Value, |
| 332 | 332 |
LastIndex: pair.ModifyIndex, |
| 333 | 333 |
}) |
| 334 | 334 |
} |
| 335 |
- watchCh <- kv |
|
| 335 |
+ watchCh <- kvpairs |
|
| 336 | 336 |
} |
| 337 | 337 |
}() |
| 338 | 338 |
|
| ... | ... |
@@ -374,11 +375,16 @@ func (l *consulLock) Unlock() error {
|
| 374 | 374 |
// AtomicPut put a value at "key" if the key has not been |
| 375 | 375 |
// modified in the meantime, throws an error if this is the case |
| 376 | 376 |
func (s *Consul) AtomicPut(key string, value []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
|
| 377 |
+ |
|
| 378 |
+ p := &api.KVPair{Key: s.normalize(key), Value: value}
|
|
| 379 |
+ |
|
| 377 | 380 |
if previous == nil {
|
| 378 |
- return false, nil, store.ErrPreviousNotSpecified |
|
| 381 |
+ // Consul interprets ModifyIndex = 0 as new key. |
|
| 382 |
+ p.ModifyIndex = 0 |
|
| 383 |
+ } else {
|
|
| 384 |
+ p.ModifyIndex = previous.LastIndex |
|
| 379 | 385 |
} |
| 380 | 386 |
|
| 381 |
- p := &api.KVPair{Key: s.normalize(key), Value: value, ModifyIndex: previous.LastIndex}
|
|
| 382 | 387 |
if work, _, err := s.client.KV().CAS(p, nil); err != nil {
|
| 383 | 388 |
return false, nil, err |
| 384 | 389 |
} else if !work {
|
| ... | ... |
@@ -278,11 +278,32 @@ func (s *Etcd) WatchTree(directory string, stopCh <-chan struct{}) (<-chan []*st
|
| 278 | 278 |
// AtomicPut put a value at "key" if the key has not been |
| 279 | 279 |
// modified in the meantime, throws an error if this is the case |
| 280 | 280 |
func (s *Etcd) AtomicPut(key string, value []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
|
| 281 |
- if previous == nil {
|
|
| 282 |
- return false, nil, store.ErrPreviousNotSpecified |
|
| 283 |
- } |
|
| 284 | 281 |
|
| 285 |
- meta, err := s.client.CompareAndSwap(store.Normalize(key), string(value), 0, "", previous.LastIndex) |
|
| 282 |
+ var meta *etcd.Response |
|
| 283 |
+ var err error |
|
| 284 |
+ if previous != nil {
|
|
| 285 |
+ meta, err = s.client.CompareAndSwap(store.Normalize(key), string(value), 0, "", previous.LastIndex) |
|
| 286 |
+ } else {
|
|
| 287 |
+ // Interpret previous == nil as Atomic Create |
|
| 288 |
+ meta, err = s.client.Create(store.Normalize(key), string(value), 0) |
|
| 289 |
+ if etcdError, ok := err.(*etcd.EtcdError); ok {
|
|
| 290 |
+ |
|
| 291 |
+ // Directory doesn't exist. |
|
| 292 |
+ if etcdError.ErrorCode == 104 {
|
|
| 293 |
+ // Remove the last element (the actual key) |
|
| 294 |
+ // and create the full directory path |
|
| 295 |
+ err = s.createDirectory(store.GetDirectory(key)) |
|
| 296 |
+ if err != nil {
|
|
| 297 |
+ return false, nil, err |
|
| 298 |
+ } |
|
| 299 |
+ |
|
| 300 |
+ // Now that the directory is created, create the key |
|
| 301 |
+ if _, err := s.client.Create(key, string(value), 0); err != nil {
|
|
| 302 |
+ return false, nil, err |
|
| 303 |
+ } |
|
| 304 |
+ } |
|
| 305 |
+ } |
|
| 306 |
+ } |
|
| 286 | 307 |
if err != nil {
|
| 287 | 308 |
if etcdError, ok := err.(*etcd.EtcdError); ok {
|
| 288 | 309 |
// Compare Failed |
| ... | ... |
@@ -11,11 +11,11 @@ type Backend string |
| 11 | 11 |
|
| 12 | 12 |
const ( |
| 13 | 13 |
// CONSUL backend |
| 14 |
- CONSUL = "consul" |
|
| 14 |
+ CONSUL Backend = "consul" |
|
| 15 | 15 |
// ETCD backend |
| 16 |
- ETCD = "etcd" |
|
| 16 |
+ ETCD Backend = "etcd" |
|
| 17 | 17 |
// ZK backend |
| 18 |
- ZK = "zk" |
|
| 18 |
+ ZK Backend = "zk" |
|
| 19 | 19 |
) |
| 20 | 20 |
|
| 21 | 21 |
var ( |
| ... | ... |
@@ -77,7 +77,8 @@ type Store interface {
|
| 77 | 77 |
// DeleteTree deletes a range of keys under a given directory |
| 78 | 78 |
DeleteTree(directory string) error |
| 79 | 79 |
|
| 80 |
- // Atomic operation on a single value |
|
| 80 |
+ // Atomic CAS operation on a single value. |
|
| 81 |
+ // Pass previous = nil to create a new key. |
|
| 81 | 82 |
AtomicPut(key string, value []byte, previous *KVPair, options *WriteOptions) (bool, *KVPair, error) |
| 82 | 83 |
|
| 83 | 84 |
// Atomic delete of a single value |
| ... | ... |
@@ -265,23 +265,47 @@ func (s *Zookeeper) DeleteTree(directory string) error {
|
| 265 | 265 |
// AtomicPut put a value at "key" if the key has not been |
| 266 | 266 |
// modified in the meantime, throws an error if this is the case |
| 267 | 267 |
func (s *Zookeeper) AtomicPut(key string, value []byte, previous *store.KVPair, _ *store.WriteOptions) (bool, *store.KVPair, error) {
|
| 268 |
- if previous == nil {
|
|
| 269 |
- return false, nil, store.ErrPreviousNotSpecified |
|
| 270 |
- } |
|
| 271 | 268 |
|
| 272 |
- meta, err := s.client.Set(store.Normalize(key), value, int32(previous.LastIndex)) |
|
| 273 |
- if err != nil {
|
|
| 274 |
- // Compare Failed |
|
| 275 |
- if err == zk.ErrBadVersion {
|
|
| 276 |
- return false, nil, store.ErrKeyModified |
|
| 269 |
+ var lastIndex uint64 |
|
| 270 |
+ if previous != nil {
|
|
| 271 |
+ meta, err := s.client.Set(store.Normalize(key), value, int32(previous.LastIndex)) |
|
| 272 |
+ if err != nil {
|
|
| 273 |
+ // Compare Failed |
|
| 274 |
+ if err == zk.ErrBadVersion {
|
|
| 275 |
+ return false, nil, store.ErrKeyModified |
|
| 276 |
+ } |
|
| 277 |
+ return false, nil, err |
|
| 277 | 278 |
} |
| 278 |
- return false, nil, err |
|
| 279 |
+ lastIndex = uint64(meta.Version) |
|
| 280 |
+ } else {
|
|
| 281 |
+ // Interpret previous == nil as create operation. |
|
| 282 |
+ _, err := s.client.Create(store.Normalize(key), value, 0, zk.WorldACL(zk.PermAll)) |
|
| 283 |
+ if err != nil {
|
|
| 284 |
+ // Zookeeper will complain if the directory doesn't exist. |
|
| 285 |
+ if err == zk.ErrNoNode {
|
|
| 286 |
+ // Create the directory |
|
| 287 |
+ parts := store.SplitKey(key) |
|
| 288 |
+ parts = parts[:len(parts)-1] |
|
| 289 |
+ if err = s.createFullPath(parts, false); err != nil {
|
|
| 290 |
+ // Failed to create the directory. |
|
| 291 |
+ return false, nil, err |
|
| 292 |
+ } |
|
| 293 |
+ if _, err := s.client.Create(store.Normalize(key), value, 0, zk.WorldACL(zk.PermAll)); err != nil {
|
|
| 294 |
+ return false, nil, err |
|
| 295 |
+ } |
|
| 296 |
+ |
|
| 297 |
+ } else {
|
|
| 298 |
+ // Unhandled error |
|
| 299 |
+ return false, nil, err |
|
| 300 |
+ } |
|
| 301 |
+ } |
|
| 302 |
+ lastIndex = 0 // Newly created nodes have version 0. |
|
| 279 | 303 |
} |
| 280 | 304 |
|
| 281 | 305 |
pair := &store.KVPair{
|
| 282 | 306 |
Key: key, |
| 283 | 307 |
Value: value, |
| 284 |
- LastIndex: uint64(meta.Version), |
|
| 308 |
+ LastIndex: lastIndex, |
|
| 285 | 309 |
} |
| 286 | 310 |
|
| 287 | 311 |
return true, pair, nil |
| ... | ... |
@@ -1,10 +1,6 @@ |
| 1 | 1 |
# Roadmap |
| 2 | 2 |
|
| 3 |
-Libnetwork is a young project and is still being defined. |
|
| 4 |
-This document defines the high-level goals of the project and defines the release-relationship to the Docker Platform. |
|
| 5 |
- |
|
| 6 |
-* [Goals](#goals) |
|
| 7 |
-* [Project Planning](#project-planning): release-relationship to the Docker Platform. |
|
| 3 |
+This document defines the high-level goals of the libnetwork project. See [Project Planning](#project-planning) for information on Releases. |
|
| 8 | 4 |
|
| 9 | 5 |
## Long-term Goal |
| 10 | 6 |
|
| ... | ... |
@@ -18,12 +14,7 @@ libnetwork aims to satisfy that composable need for Networking in Containers. |
| 18 | 18 |
- Define a flexible model that allows local and remote drivers to provide networking to containers |
| 19 | 19 |
- Provide a stand-alone tool "dnet" for managing and testing libnetwork |
| 20 | 20 |
|
| 21 |
-## Project Planning |
|
| 22 |
- |
|
| 23 |
-Libnetwork versions do not map 1:1 with Docker Platform releases. |
|
| 24 |
-Milestones and Project Pages are used to define the set of features that are included in each release. |
|
| 21 |
+Project Planning |
|
| 22 |
+================ |
|
| 25 | 23 |
|
| 26 |
-| Platform Version | Libnetwork Version | Planning | |
|
| 27 |
-|------------------|--------------------|----------| |
|
| 28 |
-| 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) | |
|
| 29 |
-| 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) | |
|
| 24 |
+[Project Pages](https://github.com/docker/libnetwork/wiki) define the goals for each Milestone and identify the release-relationship to the Docker Platform. |
| ... | ... |
@@ -55,12 +55,11 @@ func NewHandle(app string, ds datastore.DataStore, id string, numElements uint32 |
| 55 | 55 |
h.watchForChanges() |
| 56 | 56 |
|
| 57 | 57 |
// Get the initial status from the ds if present. |
| 58 |
- err := h.store.GetObject(datastore.Key(h.Key()...), h) |
|
| 59 |
- if err != datastore.ErrKeyNotFound {
|
|
| 58 |
+ if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
|
|
| 60 | 59 |
return nil, err |
| 61 | 60 |
} |
| 62 | 61 |
|
| 63 |
- return h, err |
|
| 62 |
+ return h, nil |
|
| 64 | 63 |
} |
| 65 | 64 |
|
| 66 | 65 |
// Sequence reresents a recurring sequence of 32 bits long bitmasks |
| ... | ... |
@@ -40,7 +40,12 @@ func (h *Handle) Value() []byte {
|
| 40 | 40 |
|
| 41 | 41 |
// SetValue unmarshals the data from the KV store |
| 42 | 42 |
func (h *Handle) SetValue(value []byte) error {
|
| 43 |
- return h.FromByteArray(value) |
|
| 43 |
+ var b []byte |
|
| 44 |
+ if err := json.Unmarshal(value, &b); err != nil {
|
|
| 45 |
+ return err |
|
| 46 |
+ } |
|
| 47 |
+ |
|
| 48 |
+ return h.FromByteArray(b) |
|
| 44 | 49 |
} |
| 45 | 50 |
|
| 46 | 51 |
// Index returns the latest DB Index as seen by this object |
| ... | ... |
@@ -2,12 +2,14 @@ package bridge |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"errors" |
| 5 |
+ "fmt" |
|
| 5 | 6 |
"net" |
| 6 | 7 |
"os/exec" |
| 7 | 8 |
"strconv" |
| 8 | 9 |
"sync" |
| 9 | 10 |
|
| 10 | 11 |
"github.com/Sirupsen/logrus" |
| 12 |
+ bri "github.com/docker/libcontainer/netlink" |
|
| 11 | 13 |
"github.com/docker/libnetwork/driverapi" |
| 12 | 14 |
"github.com/docker/libnetwork/ipallocator" |
| 13 | 15 |
"github.com/docker/libnetwork/iptables" |
| ... | ... |
@@ -754,6 +756,20 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
|
| 754 | 754 |
return err |
| 755 | 755 |
} |
| 756 | 756 |
|
| 757 |
+func addToBridge(ifaceName, bridgeName string) error {
|
|
| 758 |
+ iface, err := net.InterfaceByName(ifaceName) |
|
| 759 |
+ if err != nil {
|
|
| 760 |
+ return fmt.Errorf("could not find interface %s: %v", ifaceName, err)
|
|
| 761 |
+ } |
|
| 762 |
+ |
|
| 763 |
+ master, err := net.InterfaceByName(bridgeName) |
|
| 764 |
+ if err != nil {
|
|
| 765 |
+ return fmt.Errorf("could not find bridge %s: %v", bridgeName, err)
|
|
| 766 |
+ } |
|
| 767 |
+ |
|
| 768 |
+ return bri.AddToBridge(iface, master) |
|
| 769 |
+} |
|
| 770 |
+ |
|
| 757 | 771 |
func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
| 758 | 772 |
var ( |
| 759 | 773 |
ipv6Addr *net.IPNet |
| ... | ... |
@@ -821,27 +837,27 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn |
| 821 | 821 |
}() |
| 822 | 822 |
|
| 823 | 823 |
// Generate a name for what will be the host side pipe interface |
| 824 |
- name1, err := netutils.GenerateIfaceName(vethPrefix, vethLen) |
|
| 824 |
+ hostIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen) |
|
| 825 | 825 |
if err != nil {
|
| 826 | 826 |
return err |
| 827 | 827 |
} |
| 828 | 828 |
|
| 829 | 829 |
// Generate a name for what will be the sandbox side pipe interface |
| 830 |
- name2, err := netutils.GenerateIfaceName(vethPrefix, vethLen) |
|
| 830 |
+ containerIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen) |
|
| 831 | 831 |
if err != nil {
|
| 832 | 832 |
return err |
| 833 | 833 |
} |
| 834 | 834 |
|
| 835 | 835 |
// Generate and add the interface pipe host <-> sandbox |
| 836 | 836 |
veth := &netlink.Veth{
|
| 837 |
- LinkAttrs: netlink.LinkAttrs{Name: name1, TxQLen: 0},
|
|
| 838 |
- PeerName: name2} |
|
| 837 |
+ LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0},
|
|
| 838 |
+ PeerName: containerIfName} |
|
| 839 | 839 |
if err = netlink.LinkAdd(veth); err != nil {
|
| 840 | 840 |
return err |
| 841 | 841 |
} |
| 842 | 842 |
|
| 843 | 843 |
// Get the host side pipe interface handler |
| 844 |
- host, err := netlink.LinkByName(name1) |
|
| 844 |
+ host, err := netlink.LinkByName(hostIfName) |
|
| 845 | 845 |
if err != nil {
|
| 846 | 846 |
return err |
| 847 | 847 |
} |
| ... | ... |
@@ -852,7 +868,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn |
| 852 | 852 |
}() |
| 853 | 853 |
|
| 854 | 854 |
// Get the sandbox side pipe interface handler |
| 855 |
- sbox, err := netlink.LinkByName(name2) |
|
| 855 |
+ sbox, err := netlink.LinkByName(containerIfName) |
|
| 856 | 856 |
if err != nil {
|
| 857 | 857 |
return err |
| 858 | 858 |
} |
| ... | ... |
@@ -879,9 +895,8 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn |
| 879 | 879 |
} |
| 880 | 880 |
|
| 881 | 881 |
// Attach host side pipe interface into the bridge |
| 882 |
- if err = netlink.LinkSetMaster(host, |
|
| 883 |
- &netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: config.BridgeName}}); err != nil {
|
|
| 884 |
- return err |
|
| 882 |
+ if err = addToBridge(hostIfName, config.BridgeName); err != nil {
|
|
| 883 |
+ return fmt.Errorf("adding interface %s to bridge %s failed: %v", hostIfName, config.BridgeName, err)
|
|
| 885 | 884 |
} |
| 886 | 885 |
|
| 887 | 886 |
if !config.EnableUserlandProxy {
|
| ... | ... |
@@ -898,14 +913,24 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn |
| 898 | 898 |
} |
| 899 | 899 |
ipv4Addr := &net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
|
| 900 | 900 |
|
| 901 |
+ // Down the interface before configuring mac address. |
|
| 902 |
+ if err := netlink.LinkSetDown(sbox); err != nil {
|
|
| 903 |
+ return fmt.Errorf("could not set link down for container interface %s: %v", containerIfName, err)
|
|
| 904 |
+ } |
|
| 905 |
+ |
|
| 901 | 906 |
// Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP. |
| 902 | 907 |
mac := electMacAddress(epConfig, ip4) |
| 903 | 908 |
err = netlink.LinkSetHardwareAddr(sbox, mac) |
| 904 | 909 |
if err != nil {
|
| 905 |
- return err |
|
| 910 |
+ return fmt.Errorf("could not set mac address for container interface %s: %v", containerIfName, err)
|
|
| 906 | 911 |
} |
| 907 | 912 |
endpoint.macAddress = mac |
| 908 | 913 |
|
| 914 |
+ // Up the host interface after finishing all netlink configuration |
|
| 915 |
+ if err := netlink.LinkSetUp(host); err != nil {
|
|
| 916 |
+ return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err)
|
|
| 917 |
+ } |
|
| 918 |
+ |
|
| 909 | 919 |
// v6 address for the sandbox side pipe interface |
| 910 | 920 |
ipv6Addr = &net.IPNet{}
|
| 911 | 921 |
if config.EnableIPv6 {
|
| ... | ... |
@@ -934,7 +959,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn |
| 934 | 934 |
} |
| 935 | 935 |
|
| 936 | 936 |
// Create the sandbox side pipe interface |
| 937 |
- endpoint.srcName = name2 |
|
| 937 |
+ endpoint.srcName = containerIfName |
|
| 938 | 938 |
endpoint.addr = ipv4Addr |
| 939 | 939 |
|
| 940 | 940 |
if config.EnableIPv6 {
|
| ... | ... |
@@ -1,15 +1,15 @@ |
| 1 | 1 |
package bridge |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- log "github.com/Sirupsen/logrus" |
|
| 5 | 4 |
"github.com/docker/docker/pkg/parsers/kernel" |
| 6 |
- "github.com/docker/libnetwork/netutils" |
|
| 7 |
- "github.com/docker/libnetwork/types" |
|
| 5 |
+ bri "github.com/docker/libcontainer/netlink" |
|
| 8 | 6 |
"github.com/vishvananda/netlink" |
| 9 | 7 |
) |
| 10 | 8 |
|
| 11 | 9 |
// SetupDevice create a new bridge interface/ |
| 12 | 10 |
func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
|
| 11 |
+ var setMac bool |
|
| 12 |
+ |
|
| 13 | 13 |
// We only attempt to create the bridge when the requested device name is |
| 14 | 14 |
// the default one. |
| 15 | 15 |
if config.BridgeName != DefaultBridgeName && !config.AllowNonDefaultBridge {
|
| ... | ... |
@@ -27,15 +27,10 @@ func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
|
| 27 | 27 |
// was not supported before that. |
| 28 | 28 |
kv, err := kernel.GetKernelVersion() |
| 29 | 29 |
if err == nil && (kv.Kernel >= 3 && kv.Major >= 3) {
|
| 30 |
- i.Link.Attrs().HardwareAddr = netutils.GenerateRandomMAC() |
|
| 31 |
- log.Debugf("Setting bridge mac address to %s", i.Link.Attrs().HardwareAddr)
|
|
| 30 |
+ setMac = true |
|
| 32 | 31 |
} |
| 33 | 32 |
|
| 34 |
- // Call out to netlink to create the device. |
|
| 35 |
- if err = netlink.LinkAdd(i.Link); err != nil {
|
|
| 36 |
- return types.InternalErrorf("Failed to program bridge link: %s", err.Error())
|
|
| 37 |
- } |
|
| 38 |
- return nil |
|
| 33 |
+ return bri.CreateBridge(config.BridgeName, setMac) |
|
| 39 | 34 |
} |
| 40 | 35 |
|
| 41 | 36 |
// SetupDeviceUp ups the given bridge interface. |
| ... | ... |
@@ -57,7 +57,11 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
|
| 57 | 57 |
|
| 58 | 58 |
// Join method is invoked when a Sandbox is attached to an endpoint. |
| 59 | 59 |
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
| 60 |
- return (jinfo.SetHostsPath("/etc/hosts"))
|
|
| 60 |
+ if err := jinfo.SetHostsPath("/etc/hosts"); err != nil {
|
|
| 61 |
+ return err |
|
| 62 |
+ } |
|
| 63 |
+ |
|
| 64 |
+ return jinfo.SetResolvConfPath("/etc/resolv.conf")
|
|
| 61 | 65 |
} |
| 62 | 66 |
|
| 63 | 67 |
// Leave method is invoked when a Sandbox detaches from an endpoint. |
| ... | ... |
@@ -155,7 +155,7 @@ func (n *network) initSandbox() error {
|
| 155 | 155 |
|
| 156 | 156 |
func (n *network) watchMiss(nlSock *nl.NetlinkSocket) {
|
| 157 | 157 |
for {
|
| 158 |
- msgs, err := nlSock.Recieve() |
|
| 158 |
+ msgs, err := nlSock.Receive() |
|
| 159 | 159 |
if err != nil {
|
| 160 | 160 |
logrus.Errorf("Failed to receive from netlink: %v ", err)
|
| 161 | 161 |
continue |
| ... | ... |
@@ -811,9 +811,19 @@ func (ep *endpoint) updateDNS(resolvConf []byte) error {
|
| 811 | 811 |
return os.Rename(tmpResolvFile.Name(), container.config.resolvConfPath) |
| 812 | 812 |
} |
| 813 | 813 |
|
| 814 |
+func copyFile(src, dst string) error {
|
|
| 815 |
+ sBytes, err := ioutil.ReadFile(src) |
|
| 816 |
+ if err != nil {
|
|
| 817 |
+ return err |
|
| 818 |
+ } |
|
| 819 |
+ |
|
| 820 |
+ return ioutil.WriteFile(dst, sBytes, 0644) |
|
| 821 |
+} |
|
| 822 |
+ |
|
| 814 | 823 |
func (ep *endpoint) setupDNS() error {
|
| 815 | 824 |
ep.Lock() |
| 816 | 825 |
container := ep.container |
| 826 |
+ joinInfo := ep.joinInfo |
|
| 817 | 827 |
ep.Unlock() |
| 818 | 828 |
|
| 819 | 829 |
if container == nil {
|
| ... | ... |
@@ -830,6 +840,14 @@ func (ep *endpoint) setupDNS() error {
|
| 830 | 830 |
return err |
| 831 | 831 |
} |
| 832 | 832 |
|
| 833 |
+ if joinInfo.resolvConfPath != "" {
|
|
| 834 |
+ if err := copyFile(joinInfo.resolvConfPath, container.config.resolvConfPath); err != nil {
|
|
| 835 |
+ return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", joinInfo.resolvConfPath, container.config.resolvConfPath, err)
|
|
| 836 |
+ } |
|
| 837 |
+ |
|
| 838 |
+ return nil |
|
| 839 |
+ } |
|
| 840 |
+ |
|
| 833 | 841 |
resolvConf, err := resolvconf.Get() |
| 834 | 842 |
if err != nil {
|
| 835 | 843 |
return err |
| ... | ... |
@@ -43,13 +43,19 @@ import ( |
| 43 | 43 |
) |
| 44 | 44 |
|
| 45 | 45 |
func main() {
|
| 46 |
- mybridge := &netlink.Bridge{netlink.LinkAttrs{Name: "foo"}}
|
|
| 46 |
+ la := netlink.NewLinkAttrs() |
|
| 47 |
+ la.Name = "foo" |
|
| 48 |
+ mybridge := &netlink.Bridge{la}}
|
|
| 47 | 49 |
_ := netlink.LinkAdd(mybridge) |
| 48 | 50 |
eth1, _ := netlink.LinkByName("eth1")
|
| 49 | 51 |
netlink.LinkSetMaster(eth1, mybridge) |
| 50 | 52 |
} |
| 51 | 53 |
|
| 52 | 54 |
``` |
| 55 |
+Note `NewLinkAttrs` constructor, it sets default values in structure. For now |
|
| 56 |
+it sets only `TxQLen` to `-1`, so kernel will set default by itself. If you're |
|
| 57 |
+using simple initialization(`LinkAttrs{Name: "foo"}`) `TxQLen` will be set to
|
|
| 58 |
+`0` unless you specify it like `LinkAttrs{Name: "foo", TxQLen: 1000}`.
|
|
| 53 | 59 |
|
| 54 | 60 |
Add a new ip address to loopback: |
| 55 | 61 |
|
| ... | ... |
@@ -14,8 +14,8 @@ type Addr struct {
|
| 14 | 14 |
} |
| 15 | 15 |
|
| 16 | 16 |
// String returns $ip/$netmask $label |
| 17 |
-func (addr Addr) String() string {
|
|
| 18 |
- return fmt.Sprintf("%s %s", addr.IPNet, addr.Label)
|
|
| 17 |
+func (a Addr) String() string {
|
|
| 18 |
+ return fmt.Sprintf("%s %s", a.IPNet, a.Label)
|
|
| 19 | 19 |
} |
| 20 | 20 |
|
| 21 | 21 |
// ParseAddr parses the string representation of an address in the |
| ... | ... |
@@ -81,7 +81,7 @@ func AddrList(link Link, family int) ([]Addr, error) {
|
| 81 | 81 |
index = base.Index |
| 82 | 82 |
} |
| 83 | 83 |
|
| 84 |
- res := make([]Addr, 0) |
|
| 84 |
+ var res []Addr |
|
| 85 | 85 |
for _, m := range msgs {
|
| 86 | 86 |
msg := nl.DeserializeIfAddrmsg(m) |
| 87 | 87 |
|
| ... | ... |
@@ -95,11 +95,17 @@ func AddrList(link Link, family int) ([]Addr, error) {
|
| 95 | 95 |
return nil, err |
| 96 | 96 |
} |
| 97 | 97 |
|
| 98 |
+ var local, dst *net.IPNet |
|
| 98 | 99 |
var addr Addr |
| 99 | 100 |
for _, attr := range attrs {
|
| 100 | 101 |
switch attr.Attr.Type {
|
| 101 | 102 |
case syscall.IFA_ADDRESS: |
| 102 |
- addr.IPNet = &net.IPNet{
|
|
| 103 |
+ dst = &net.IPNet{
|
|
| 104 |
+ IP: attr.Value, |
|
| 105 |
+ Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)), |
|
| 106 |
+ } |
|
| 107 |
+ case syscall.IFA_LOCAL: |
|
| 108 |
+ local = &net.IPNet{
|
|
| 103 | 109 |
IP: attr.Value, |
| 104 | 110 |
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)), |
| 105 | 111 |
} |
| ... | ... |
@@ -107,6 +113,14 @@ func AddrList(link Link, family int) ([]Addr, error) {
|
| 107 | 107 |
addr.Label = string(attr.Value[:len(attr.Value)-1]) |
| 108 | 108 |
} |
| 109 | 109 |
} |
| 110 |
+ |
|
| 111 |
+ // IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS |
|
| 112 |
+ if local != nil {
|
|
| 113 |
+ addr.IPNet = local |
|
| 114 |
+ } else {
|
|
| 115 |
+ addr.IPNet = dst |
|
| 116 |
+ } |
|
| 117 |
+ |
|
| 110 | 118 |
res = append(res, addr) |
| 111 | 119 |
} |
| 112 | 120 |
|
| ... | ... |
@@ -10,16 +10,29 @@ type Link interface {
|
| 10 | 10 |
Type() string |
| 11 | 11 |
} |
| 12 | 12 |
|
| 13 |
+type ( |
|
| 14 |
+ NsPid int |
|
| 15 |
+ NsFd int |
|
| 16 |
+) |
|
| 17 |
+ |
|
| 13 | 18 |
// LinkAttrs represents data shared by most link types |
| 14 | 19 |
type LinkAttrs struct {
|
| 15 | 20 |
Index int |
| 16 | 21 |
MTU int |
| 17 |
- TxQLen uint32 // Transmit Queue Length |
|
| 22 |
+ TxQLen int // Transmit Queue Length |
|
| 18 | 23 |
Name string |
| 19 | 24 |
HardwareAddr net.HardwareAddr |
| 20 | 25 |
Flags net.Flags |
| 21 |
- ParentIndex int // index of the parent link device |
|
| 22 |
- MasterIndex int // must be the index of a bridge |
|
| 26 |
+ ParentIndex int // index of the parent link device |
|
| 27 |
+ MasterIndex int // must be the index of a bridge |
|
| 28 |
+ Namespace interface{} // nil | NsPid | NsFd
|
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+// NewLinkAttrs returns LinkAttrs structure filled with default values |
|
| 32 |
+func NewLinkAttrs() LinkAttrs {
|
|
| 33 |
+ return LinkAttrs{
|
|
| 34 |
+ TxQLen: -1, |
|
| 35 |
+ } |
|
| 23 | 36 |
} |
| 24 | 37 |
|
| 25 | 38 |
// Device links cannot be created via netlink. These links |
| ... | ... |
@@ -76,9 +89,21 @@ func (vlan *Vlan) Type() string {
|
| 76 | 76 |
return "vlan" |
| 77 | 77 |
} |
| 78 | 78 |
|
| 79 |
+type MacvlanMode uint16 |
|
| 80 |
+ |
|
| 81 |
+const ( |
|
| 82 |
+ MACVLAN_MODE_DEFAULT MacvlanMode = iota |
|
| 83 |
+ MACVLAN_MODE_PRIVATE |
|
| 84 |
+ MACVLAN_MODE_VEPA |
|
| 85 |
+ MACVLAN_MODE_BRIDGE |
|
| 86 |
+ MACVLAN_MODE_PASSTHRU |
|
| 87 |
+ MACVLAN_MODE_SOURCE |
|
| 88 |
+) |
|
| 89 |
+ |
|
| 79 | 90 |
// Macvlan links have ParentIndex set in their Attrs() |
| 80 | 91 |
type Macvlan struct {
|
| 81 | 92 |
LinkAttrs |
| 93 |
+ Mode MacvlanMode |
|
| 82 | 94 |
} |
| 83 | 95 |
|
| 84 | 96 |
func (macvlan *Macvlan) Attrs() *LinkAttrs {
|
| ... | ... |
@@ -13,6 +13,15 @@ import ( |
| 13 | 13 |
var native = nl.NativeEndian() |
| 14 | 14 |
var lookupByDump = false |
| 15 | 15 |
|
| 16 |
+var macvlanModes = [...]uint32{
|
|
| 17 |
+ 0, |
|
| 18 |
+ nl.MACVLAN_MODE_PRIVATE, |
|
| 19 |
+ nl.MACVLAN_MODE_VEPA, |
|
| 20 |
+ nl.MACVLAN_MODE_BRIDGE, |
|
| 21 |
+ nl.MACVLAN_MODE_PASSTHRU, |
|
| 22 |
+ nl.MACVLAN_MODE_SOURCE, |
|
| 23 |
+} |
|
| 24 |
+ |
|
| 16 | 25 |
func ensureIndex(link *LinkAttrs) {
|
| 17 | 26 |
if link != nil && link.Index == 0 {
|
| 18 | 27 |
newlink, _ := LinkByName(link.Name) |
| ... | ... |
@@ -39,7 +48,7 @@ func LinkSetUp(link Link) error {
|
| 39 | 39 |
return err |
| 40 | 40 |
} |
| 41 | 41 |
|
| 42 |
-// LinkSetUp disables link device. |
|
| 42 |
+// LinkSetDown disables link device. |
|
| 43 | 43 |
// Equivalent to: `ip link set $link down` |
| 44 | 44 |
func LinkSetDown(link Link) error {
|
| 45 | 45 |
base := link.Attrs() |
| ... | ... |
@@ -67,7 +76,7 @@ func LinkSetMTU(link Link, mtu int) error {
|
| 67 | 67 |
msg.Type = syscall.RTM_SETLINK |
| 68 | 68 |
msg.Flags = syscall.NLM_F_REQUEST |
| 69 | 69 |
msg.Index = int32(base.Index) |
| 70 |
- msg.Change = nl.DEFAULT_CHANGE |
|
| 70 |
+ msg.Change = syscall.IFLA_MTU |
|
| 71 | 71 |
req.AddData(msg) |
| 72 | 72 |
|
| 73 | 73 |
b := make([]byte, 4) |
| ... | ... |
@@ -91,7 +100,7 @@ func LinkSetName(link Link, name string) error {
|
| 91 | 91 |
msg.Type = syscall.RTM_SETLINK |
| 92 | 92 |
msg.Flags = syscall.NLM_F_REQUEST |
| 93 | 93 |
msg.Index = int32(base.Index) |
| 94 |
- msg.Change = nl.DEFAULT_CHANGE |
|
| 94 |
+ msg.Change = syscall.IFLA_IFNAME |
|
| 95 | 95 |
req.AddData(msg) |
| 96 | 96 |
|
| 97 | 97 |
data := nl.NewRtAttr(syscall.IFLA_IFNAME, []byte(name)) |
| ... | ... |
@@ -112,7 +121,7 @@ func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
|
| 112 | 112 |
msg.Type = syscall.RTM_SETLINK |
| 113 | 113 |
msg.Flags = syscall.NLM_F_REQUEST |
| 114 | 114 |
msg.Index = int32(base.Index) |
| 115 |
- msg.Change = nl.DEFAULT_CHANGE |
|
| 115 |
+ msg.Change = syscall.IFLA_ADDRESS |
|
| 116 | 116 |
req.AddData(msg) |
| 117 | 117 |
|
| 118 | 118 |
data := nl.NewRtAttr(syscall.IFLA_ADDRESS, []byte(hwaddr)) |
| ... | ... |
@@ -145,7 +154,7 @@ func LinkSetMasterByIndex(link Link, masterIndex int) error {
|
| 145 | 145 |
msg.Type = syscall.RTM_SETLINK |
| 146 | 146 |
msg.Flags = syscall.NLM_F_REQUEST |
| 147 | 147 |
msg.Index = int32(base.Index) |
| 148 |
- msg.Change = nl.DEFAULT_CHANGE |
|
| 148 |
+ msg.Change = syscall.IFLA_MASTER |
|
| 149 | 149 |
req.AddData(msg) |
| 150 | 150 |
|
| 151 | 151 |
b := make([]byte, 4) |
| ... | ... |
@@ -170,7 +179,7 @@ func LinkSetNsPid(link Link, nspid int) error {
|
| 170 | 170 |
msg.Type = syscall.RTM_SETLINK |
| 171 | 171 |
msg.Flags = syscall.NLM_F_REQUEST |
| 172 | 172 |
msg.Index = int32(base.Index) |
| 173 |
- msg.Change = nl.DEFAULT_CHANGE |
|
| 173 |
+ msg.Change = syscall.IFLA_NET_NS_PID |
|
| 174 | 174 |
req.AddData(msg) |
| 175 | 175 |
|
| 176 | 176 |
b := make([]byte, 4) |
| ... | ... |
@@ -183,7 +192,7 @@ func LinkSetNsPid(link Link, nspid int) error {
|
| 183 | 183 |
return err |
| 184 | 184 |
} |
| 185 | 185 |
|
| 186 |
-// LinkSetNsPid puts the device into a new network namespace. The |
|
| 186 |
+// LinkSetNsFd puts the device into a new network namespace. The |
|
| 187 | 187 |
// fd must be an open file descriptor to a network namespace. |
| 188 | 188 |
// Similar to: `ip link set $link netns $ns` |
| 189 | 189 |
func LinkSetNsFd(link Link, fd int) error {
|
| ... | ... |
@@ -195,7 +204,7 @@ func LinkSetNsFd(link Link, fd int) error {
|
| 195 | 195 |
msg.Type = syscall.RTM_SETLINK |
| 196 | 196 |
msg.Flags = syscall.NLM_F_REQUEST |
| 197 | 197 |
msg.Index = int32(base.Index) |
| 198 |
- msg.Change = nl.DEFAULT_CHANGE |
|
| 198 |
+ msg.Change = nl.IFLA_NET_NS_FD |
|
| 199 | 199 |
req.AddData(msg) |
| 200 | 200 |
|
| 201 | 201 |
b := make([]byte, 4) |
| ... | ... |
@@ -312,11 +321,28 @@ func LinkAdd(link Link) error {
|
| 312 | 312 |
req.AddData(mtu) |
| 313 | 313 |
} |
| 314 | 314 |
|
| 315 |
+ if base.TxQLen >= 0 {
|
|
| 316 |
+ qlen := nl.NewRtAttr(syscall.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen))) |
|
| 317 |
+ req.AddData(qlen) |
|
| 318 |
+ } |
|
| 319 |
+ |
|
| 320 |
+ if base.Namespace != nil {
|
|
| 321 |
+ var attr *nl.RtAttr |
|
| 322 |
+ switch base.Namespace.(type) {
|
|
| 323 |
+ case NsPid: |
|
| 324 |
+ val := nl.Uint32Attr(uint32(base.Namespace.(NsPid))) |
|
| 325 |
+ attr = nl.NewRtAttr(syscall.IFLA_NET_NS_PID, val) |
|
| 326 |
+ case NsFd: |
|
| 327 |
+ val := nl.Uint32Attr(uint32(base.Namespace.(NsFd))) |
|
| 328 |
+ attr = nl.NewRtAttr(nl.IFLA_NET_NS_FD, val) |
|
| 329 |
+ } |
|
| 330 |
+ |
|
| 331 |
+ req.AddData(attr) |
|
| 332 |
+ } |
|
| 333 |
+ |
|
| 315 | 334 |
linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil) |
| 316 | 335 |
nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type())) |
| 317 | 336 |
|
| 318 |
- nl.NewRtAttrChild(linkInfo, syscall.IFLA_TXQLEN, nl.Uint32Attr(base.TxQLen)) |
|
| 319 |
- |
|
| 320 | 337 |
if vlan, ok := link.(*Vlan); ok {
|
| 321 | 338 |
b := make([]byte, 2) |
| 322 | 339 |
native.PutUint16(b, uint16(vlan.VlanId)) |
| ... | ... |
@@ -327,15 +353,23 @@ func LinkAdd(link Link) error {
|
| 327 | 327 |
peer := nl.NewRtAttrChild(data, nl.VETH_INFO_PEER, nil) |
| 328 | 328 |
nl.NewIfInfomsgChild(peer, syscall.AF_UNSPEC) |
| 329 | 329 |
nl.NewRtAttrChild(peer, syscall.IFLA_IFNAME, nl.ZeroTerminated(veth.PeerName)) |
| 330 |
- nl.NewRtAttrChild(peer, syscall.IFLA_TXQLEN, nl.Uint32Attr(base.TxQLen)) |
|
| 330 |
+ if base.TxQLen >= 0 {
|
|
| 331 |
+ nl.NewRtAttrChild(peer, syscall.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen))) |
|
| 332 |
+ } |
|
| 331 | 333 |
if base.MTU > 0 {
|
| 332 | 334 |
nl.NewRtAttrChild(peer, syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU))) |
| 333 | 335 |
} |
| 336 |
+ |
|
| 334 | 337 |
} else if vxlan, ok := link.(*Vxlan); ok {
|
| 335 | 338 |
addVxlanAttrs(vxlan, linkInfo) |
| 336 | 339 |
} else if ipv, ok := link.(*IPVlan); ok {
|
| 337 | 340 |
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) |
| 338 | 341 |
nl.NewRtAttrChild(data, nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(ipv.Mode))) |
| 342 |
+ } else if macv, ok := link.(*Macvlan); ok {
|
|
| 343 |
+ if macv.Mode != MACVLAN_MODE_DEFAULT {
|
|
| 344 |
+ data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) |
|
| 345 |
+ nl.NewRtAttrChild(data, nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[macv.Mode])) |
|
| 346 |
+ } |
|
| 339 | 347 |
} |
| 340 | 348 |
|
| 341 | 349 |
req.AddData(linkInfo) |
| ... | ... |
@@ -483,6 +517,8 @@ func linkDeserialize(m []byte) (Link, error) {
|
| 483 | 483 |
link = &Vxlan{}
|
| 484 | 484 |
case "ipvlan": |
| 485 | 485 |
link = &IPVlan{}
|
| 486 |
+ case "macvlan": |
|
| 487 |
+ link = &Macvlan{}
|
|
| 486 | 488 |
default: |
| 487 | 489 |
link = &Generic{LinkType: linkType}
|
| 488 | 490 |
} |
| ... | ... |
@@ -498,6 +534,8 @@ func linkDeserialize(m []byte) (Link, error) {
|
| 498 | 498 |
parseVxlanData(link, data) |
| 499 | 499 |
case "ipvlan": |
| 500 | 500 |
parseIPVlanData(link, data) |
| 501 |
+ case "macvlan": |
|
| 502 |
+ parseMacvlanData(link, data) |
|
| 501 | 503 |
} |
| 502 | 504 |
} |
| 503 | 505 |
} |
| ... | ... |
@@ -520,7 +558,7 @@ func linkDeserialize(m []byte) (Link, error) {
|
| 520 | 520 |
case syscall.IFLA_MASTER: |
| 521 | 521 |
base.MasterIndex = int(native.Uint32(attr.Value[0:4])) |
| 522 | 522 |
case syscall.IFLA_TXQLEN: |
| 523 |
- base.TxQLen = native.Uint32(attr.Value[0:4]) |
|
| 523 |
+ base.TxQLen = int(native.Uint32(attr.Value[0:4])) |
|
| 524 | 524 |
} |
| 525 | 525 |
} |
| 526 | 526 |
// Links that don't have IFLA_INFO_KIND are hardware devices |
| ... | ... |
@@ -547,8 +585,7 @@ func LinkList() ([]Link, error) {
|
| 547 | 547 |
return nil, err |
| 548 | 548 |
} |
| 549 | 549 |
|
| 550 |
- res := make([]Link, 0) |
|
| 551 |
- |
|
| 550 |
+ var res []Link |
|
| 552 | 551 |
for _, m := range msgs {
|
| 553 | 552 |
link, err := linkDeserialize(m) |
| 554 | 553 |
if err != nil {
|
| ... | ... |
@@ -593,7 +630,7 @@ func setProtinfoAttr(link Link, mode bool, attr int) error {
|
| 593 | 593 |
msg.Type = syscall.RTM_SETLINK |
| 594 | 594 |
msg.Flags = syscall.NLM_F_REQUEST |
| 595 | 595 |
msg.Index = int32(base.Index) |
| 596 |
- msg.Change = nl.DEFAULT_CHANGE |
|
| 596 |
+ msg.Change = syscall.IFLA_PROTINFO | syscall.NLA_F_NESTED |
|
| 597 | 597 |
req.AddData(msg) |
| 598 | 598 |
|
| 599 | 599 |
br := nl.NewRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil) |
| ... | ... |
@@ -674,6 +711,27 @@ func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
| 674 | 674 |
} |
| 675 | 675 |
} |
| 676 | 676 |
|
| 677 |
+func parseMacvlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
|
| 678 |
+ macv := link.(*Macvlan) |
|
| 679 |
+ for _, datum := range data {
|
|
| 680 |
+ if datum.Attr.Type == nl.IFLA_MACVLAN_MODE {
|
|
| 681 |
+ switch native.Uint32(datum.Value[0:4]) {
|
|
| 682 |
+ case nl.MACVLAN_MODE_PRIVATE: |
|
| 683 |
+ macv.Mode = MACVLAN_MODE_PRIVATE |
|
| 684 |
+ case nl.MACVLAN_MODE_VEPA: |
|
| 685 |
+ macv.Mode = MACVLAN_MODE_VEPA |
|
| 686 |
+ case nl.MACVLAN_MODE_BRIDGE: |
|
| 687 |
+ macv.Mode = MACVLAN_MODE_BRIDGE |
|
| 688 |
+ case nl.MACVLAN_MODE_PASSTHRU: |
|
| 689 |
+ macv.Mode = MACVLAN_MODE_PASSTHRU |
|
| 690 |
+ case nl.MACVLAN_MODE_SOURCE: |
|
| 691 |
+ macv.Mode = MACVLAN_MODE_SOURCE |
|
| 692 |
+ } |
|
| 693 |
+ return |
|
| 694 |
+ } |
|
| 695 |
+ } |
|
| 696 |
+} |
|
| 697 |
+ |
|
| 677 | 698 |
// copied from pkg/net_linux.go |
| 678 | 699 |
func linkFlags(rawFlags uint32) net.Flags {
|
| 679 | 700 |
var f net.Flags |
| ... | ... |
@@ -141,7 +141,7 @@ func NeighList(linkIndex, family int) ([]Neigh, error) {
|
| 141 | 141 |
return nil, err |
| 142 | 142 |
} |
| 143 | 143 |
|
| 144 |
- res := make([]Neigh, 0) |
|
| 144 |
+ var res []Neigh |
|
| 145 | 145 |
for _, m := range msgs {
|
| 146 | 146 |
ndm := deserializeNdmsg(m) |
| 147 | 147 |
if linkIndex != 0 && int(ndm.Index) != linkIndex {
|
| ... | ... |
@@ -79,3 +79,18 @@ const ( |
| 79 | 79 |
// not defined in syscall |
| 80 | 80 |
IFLA_NET_NS_FD = 28 |
| 81 | 81 |
) |
| 82 |
+ |
|
| 83 |
+const ( |
|
| 84 |
+ IFLA_MACVLAN_UNSPEC = iota |
|
| 85 |
+ IFLA_MACVLAN_MODE |
|
| 86 |
+ IFLA_MACVLAN_FLAGS |
|
| 87 |
+ IFLA_MACVLAN_MAX = IFLA_MACVLAN_FLAGS |
|
| 88 |
+) |
|
| 89 |
+ |
|
| 90 |
+const ( |
|
| 91 |
+ MACVLAN_MODE_PRIVATE = 1 |
|
| 92 |
+ MACVLAN_MODE_VEPA = 2 |
|
| 93 |
+ MACVLAN_MODE_BRIDGE = 4 |
|
| 94 |
+ MACVLAN_MODE_PASSTHRU = 8 |
|
| 95 |
+ MACVLAN_MODE_SOURCE = 16 |
|
| 96 |
+) |
| ... | ... |
@@ -172,16 +172,16 @@ type NetlinkRequest struct {
|
| 172 | 172 |
} |
| 173 | 173 |
|
| 174 | 174 |
// Serialize the Netlink Request into a byte array |
| 175 |
-func (msg *NetlinkRequest) Serialize() []byte {
|
|
| 175 |
+func (req *NetlinkRequest) Serialize() []byte {
|
|
| 176 | 176 |
length := syscall.SizeofNlMsghdr |
| 177 |
- dataBytes := make([][]byte, len(msg.Data)) |
|
| 178 |
- for i, data := range msg.Data {
|
|
| 177 |
+ dataBytes := make([][]byte, len(req.Data)) |
|
| 178 |
+ for i, data := range req.Data {
|
|
| 179 | 179 |
dataBytes[i] = data.Serialize() |
| 180 | 180 |
length = length + len(dataBytes[i]) |
| 181 | 181 |
} |
| 182 |
- msg.Len = uint32(length) |
|
| 182 |
+ req.Len = uint32(length) |
|
| 183 | 183 |
b := make([]byte, length) |
| 184 |
- hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(msg)))[:] |
|
| 184 |
+ hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:] |
|
| 185 | 185 |
next := syscall.SizeofNlMsghdr |
| 186 | 186 |
copy(b[0:next], hdr) |
| 187 | 187 |
for _, data := range dataBytes {
|
| ... | ... |
@@ -193,9 +193,9 @@ func (msg *NetlinkRequest) Serialize() []byte {
|
| 193 | 193 |
return b |
| 194 | 194 |
} |
| 195 | 195 |
|
| 196 |
-func (msg *NetlinkRequest) AddData(data NetlinkRequestData) {
|
|
| 196 |
+func (req *NetlinkRequest) AddData(data NetlinkRequestData) {
|
|
| 197 | 197 |
if data != nil {
|
| 198 |
- msg.Data = append(msg.Data, data) |
|
| 198 |
+ req.Data = append(req.Data, data) |
|
| 199 | 199 |
} |
| 200 | 200 |
} |
| 201 | 201 |
|
| ... | ... |
@@ -218,11 +218,11 @@ func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, erro |
| 218 | 218 |
return nil, err |
| 219 | 219 |
} |
| 220 | 220 |
|
| 221 |
- res := make([][]byte, 0) |
|
| 221 |
+ var res [][]byte |
|
| 222 | 222 |
|
| 223 | 223 |
done: |
| 224 | 224 |
for {
|
| 225 |
- msgs, err := s.Recieve() |
|
| 225 |
+ msgs, err := s.Receive() |
|
| 226 | 226 |
if err != nil {
|
| 227 | 227 |
return nil, err |
| 228 | 228 |
} |
| ... | ... |
@@ -294,7 +294,7 @@ func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
|
| 294 | 294 |
|
| 295 | 295 |
// Create a netlink socket with a given protocol (e.g. NETLINK_ROUTE) |
| 296 | 296 |
// and subscribe it to multicast groups passed in variable argument list. |
| 297 |
-// Returns the netlink socket on whic hReceive() method can be called |
|
| 297 |
+// Returns the netlink socket on which Receive() method can be called |
|
| 298 | 298 |
// to retrieve the messages from the kernel. |
| 299 | 299 |
func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
|
| 300 | 300 |
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol) |
| ... | ... |
@@ -329,7 +329,7 @@ func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
|
| 329 | 329 |
return nil |
| 330 | 330 |
} |
| 331 | 331 |
|
| 332 |
-func (s *NetlinkSocket) Recieve() ([]syscall.NetlinkMessage, error) {
|
|
| 332 |
+func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
|
|
| 333 | 333 |
rb := make([]byte, syscall.Getpagesize()) |
| 334 | 334 |
nr, _, err := syscall.Recvfrom(s.fd, rb, 0) |
| 335 | 335 |
if err != nil {
|
| ... | ... |
@@ -104,9 +104,8 @@ func (x *XfrmAddress) ToIPNet(prefixlen uint8) *net.IPNet {
|
| 104 | 104 |
ip := x.ToIP() |
| 105 | 105 |
if GetIPFamily(ip) == FAMILY_V4 {
|
| 106 | 106 |
return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 32)}
|
| 107 |
- } else {
|
|
| 108 |
- return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 128)}
|
|
| 109 | 107 |
} |
| 108 |
+ return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 128)}
|
|
| 110 | 109 |
} |
| 111 | 110 |
|
| 112 | 111 |
func (x *XfrmAddress) FromIP(ip net.IP) {
|
| ... | ... |
@@ -125,8 +124,8 @@ func DeserializeXfrmAddress(b []byte) *XfrmAddress {
|
| 125 | 125 |
return (*XfrmAddress)(unsafe.Pointer(&b[0:SizeofXfrmAddress][0])) |
| 126 | 126 |
} |
| 127 | 127 |
|
| 128 |
-func (msg *XfrmAddress) Serialize() []byte {
|
|
| 129 |
- return (*(*[SizeofXfrmAddress]byte)(unsafe.Pointer(msg)))[:] |
|
| 128 |
+func (x *XfrmAddress) Serialize() []byte {
|
|
| 129 |
+ return (*(*[SizeofXfrmAddress]byte)(unsafe.Pointer(x)))[:] |
|
| 130 | 130 |
} |
| 131 | 131 |
|
| 132 | 132 |
// struct xfrm_selector {
|
| ... | ... |
@@ -119,7 +119,7 @@ func RouteList(link Link, family int) ([]Route, error) {
|
| 119 | 119 |
} |
| 120 | 120 |
|
| 121 | 121 |
native := nl.NativeEndian() |
| 122 |
- res := make([]Route, 0) |
|
| 122 |
+ var res []Route |
|
| 123 | 123 |
for _, m := range msgs {
|
| 124 | 124 |
msg := nl.DeserializeRtMsg(m) |
| 125 | 125 |
|
| ... | ... |
@@ -193,7 +193,7 @@ func RouteGet(destination net.IP) ([]Route, error) {
|
| 193 | 193 |
} |
| 194 | 194 |
|
| 195 | 195 |
native := nl.NativeEndian() |
| 196 |
- res := make([]Route, 0) |
|
| 196 |
+ var res []Route |
|
| 197 | 197 |
for _, m := range msgs {
|
| 198 | 198 |
msg := nl.DeserializeRtMsg(m) |
| 199 | 199 |
attrs, err := nl.ParseRouteAttr(m[msg.Len():]) |
| ... | ... |
@@ -52,33 +52,30 @@ func Get() (NsHandle, error) {
|
| 52 | 52 |
return GetFromThread(os.Getpid(), syscall.Gettid()) |
| 53 | 53 |
} |
| 54 | 54 |
|
| 55 |
-// GetFromName gets a handle to a named network namespace such as one |
|
| 56 |
-// created by `ip netns add`. |
|
| 57 |
-func GetFromName(name string) (NsHandle, error) {
|
|
| 58 |
- fd, err := syscall.Open(fmt.Sprintf("/var/run/netns/%s", name), syscall.O_RDONLY, 0)
|
|
| 55 |
+// GetFromPath gets a handle to a network namespace |
|
| 56 |
+// identified by the path |
|
| 57 |
+func GetFromPath(path string) (NsHandle, error) {
|
|
| 58 |
+ fd, err := syscall.Open(path, syscall.O_RDONLY, 0) |
|
| 59 | 59 |
if err != nil {
|
| 60 | 60 |
return -1, err |
| 61 | 61 |
} |
| 62 | 62 |
return NsHandle(fd), nil |
| 63 | 63 |
} |
| 64 | 64 |
|
| 65 |
+// GetFromName gets a handle to a named network namespace such as one |
|
| 66 |
+// created by `ip netns add`. |
|
| 67 |
+func GetFromName(name string) (NsHandle, error) {
|
|
| 68 |
+ return GetFromPath(fmt.Sprintf("/var/run/netns/%s", name))
|
|
| 69 |
+} |
|
| 70 |
+ |
|
| 65 | 71 |
// GetFromPid gets a handle to the network namespace of a given pid. |
| 66 | 72 |
func GetFromPid(pid int) (NsHandle, error) {
|
| 67 |
- fd, err := syscall.Open(fmt.Sprintf("/proc/%d/ns/net", pid), syscall.O_RDONLY, 0)
|
|
| 68 |
- if err != nil {
|
|
| 69 |
- return -1, err |
|
| 70 |
- } |
|
| 71 |
- return NsHandle(fd), nil |
|
| 73 |
+ return GetFromPath(fmt.Sprintf("/proc/%d/ns/net", pid))
|
|
| 72 | 74 |
} |
| 73 | 75 |
|
| 74 | 76 |
// GetFromThread gets a handle to the network namespace of a given pid and tid. |
| 75 | 77 |
func GetFromThread(pid, tid int) (NsHandle, error) {
|
| 76 |
- name := fmt.Sprintf("/proc/%d/task/%d/ns/net", pid, tid)
|
|
| 77 |
- fd, err := syscall.Open(name, syscall.O_RDONLY, 0) |
|
| 78 |
- if err != nil {
|
|
| 79 |
- return -1, err |
|
| 80 |
- } |
|
| 81 |
- return NsHandle(fd), nil |
|
| 78 |
+ return GetFromPath(fmt.Sprintf("/proc/%d/task/%d/ns/net", pid, tid))
|
|
| 82 | 79 |
} |
| 83 | 80 |
|
| 84 | 81 |
// GetFromDocker gets a handle to the network namespace of a docker container. |