Browse code

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>

Jana Radhakrishnan authored on 2015/07/06 16:14:20
Showing 32 changed files
... ...
@@ -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
... ...
@@ -54,6 +54,7 @@ func createVxlan(vni uint32) (string, error) {
54 54
 		LinkAttrs: netlink.LinkAttrs{Name: name},
55 55
 		VxlanId:   int(vni),
56 56
 		Learning:  true,
57
+		Port:      vxlanPort,
57 58
 		Proxy:     true,
58 59
 		L3miss:    true,
59 60
 		L2miss:    true,
... ...
@@ -21,6 +21,7 @@ const (
21 21
 	vethLen      = 7
22 22
 	vxlanIDStart = 256
23 23
 	vxlanIDEnd   = 1000
24
+	vxlanPort    = 4789
24 25
 )
25 26
 
26 27
 type driver struct {
... ...
@@ -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 {
... ...
@@ -16,7 +16,7 @@ type Protinfo struct {
16 16
 
17 17
 // String returns a list of enabled flags
18 18
 func (prot *Protinfo) String() string {
19
-	boolStrings := make([]string, 0)
19
+	var boolStrings []string
20 20
 	if prot.Hairpin {
21 21
 		boolStrings = append(boolStrings, "Hairpin")
22 22
 	}
... ...
@@ -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():])
... ...
@@ -84,7 +84,7 @@ func XfrmPolicyList(family int) ([]XfrmPolicy, error) {
84 84
 		return nil, err
85 85
 	}
86 86
 
87
-	res := make([]XfrmPolicy, 0)
87
+	var res []XfrmPolicy
88 88
 	for _, m := range msgs {
89 89
 		msg := nl.DeserializeXfrmUserpolicyInfo(m)
90 90
 
... ...
@@ -118,7 +118,7 @@ func XfrmStateList(family int) ([]XfrmState, error) {
118 118
 		return nil, err
119 119
 	}
120 120
 
121
-	res := make([]XfrmState, 0)
121
+	var res []XfrmState
122 122
 	for _, m := range msgs {
123 123
 		msg := nl.DeserializeXfrmUsersaInfo(m)
124 124
 
... ...
@@ -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.
... ...
@@ -3,5 +3,5 @@
3 3
 package netns
4 4
 
5 5
 const (
6
-	SYS_SETNS = 374
6
+	SYS_SETNS = 375
7 7
 )
8 8
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// +build linux,arm64
1
+
2
+package netns
3
+
4
+const (
5
+	SYS_SETNS = 268
6
+)