Browse code

bump libnetwork. vishvananda/netlink 1.0, vishvananda/netns

full diffs:

- https://github.com/docker/libnetwork/compare/fc5a7d91d54cc98f64fc28f9e288b46a0bee756c...62a13ae87c6058bdc000fcccbf7e0f9f7525e2a9
- https://github.com/vishvananda/netlink/compare/b2de5d10e38ecce8607e6b438b6d174f389a004e...v1.0.0
- https://github.com/vishvananda/netns/compare/604eaf189ee867d8c147fafc28def2394e878d25...13995c7128ccc8e51e9a6bd2b551020a27180abd

notable changes in libnetwork:

- docker/libnetwork#2366 Bump vishvananda/netlink to 1.0.0
- docker/libnetwork#2339 controller: Check if IPTables is enabled for arrangeUserFilterRule
- addresses docker/libnetwork#2158 dockerd when run with --iptables=false modifies iptables by adding DOCKER-USER
- addresses moby/moby#35777 With iptables=false dockerd still creates DOCKER-USER chain and rules
- addresses docker/for-linux#136 dockerd --iptables=false adds DOCKER-USER chain and modify FORWARD chain anyway
- docker/libnetwork#2394 Make DNS records and queries case-insensitive
- addresses moby/moby#28689 Embedded DNS is case-sensitive
- addresses moby/moby#21169 hostnames with new networking are case-sensitive

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 344b093258fcb2195fa393081e5224a6c766c798)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2019/04/11 02:09:53
Showing 58 changed files
... ...
@@ -3,7 +3,7 @@
3 3
 # LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When
4 4
 # updating the binary version, consider updating github.com/docker/libnetwork
5 5
 # in vendor.conf accordingly
6
-LIBNETWORK_COMMIT=fc5a7d91d54cc98f64fc28f9e288b46a0bee756c
6
+LIBNETWORK_COMMIT=62a13ae87c6058bdc000fcccbf7e0f9f7525e2a9
7 7
 
8 8
 install_proxy() {
9 9
 	case "$1" in
... ...
@@ -39,7 +39,7 @@ github.com/gofrs/flock                              7f43ea2e6a643ad441fc12d0ecc0
39 39
 # libnetwork
40 40
 
41 41
 # When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy.installer accordingly
42
-github.com/docker/libnetwork                        fc5a7d91d54cc98f64fc28f9e288b46a0bee756c
42
+github.com/docker/libnetwork                        62a13ae87c6058bdc000fcccbf7e0f9f7525e2a9
43 43
 github.com/docker/go-events                         9461782956ad83b30282bf90e31fa6a70c255ba9
44 44
 github.com/armon/go-radix                           e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
45 45
 github.com/armon/go-metrics                         eb0af217e5e9747e41dd5303755356b62d28e3ec
... ...
@@ -50,8 +50,8 @@ github.com/hashicorp/go-sockaddr                    6d291a969b86c4b633730bfc6b8b
50 50
 github.com/hashicorp/go-multierror                  fcdddc395df1ddf4247c69bd436e84cfa0733f7e
51 51
 github.com/hashicorp/serf                           598c54895cc5a7b1a24a398d635e8c0ea0959870
52 52
 github.com/docker/libkv                             458977154600b9f23984d9f4b82e79570b5ae12b
53
-github.com/vishvananda/netns                        604eaf189ee867d8c147fafc28def2394e878d25
54
-github.com/vishvananda/netlink                      b2de5d10e38ecce8607e6b438b6d174f389a004e
53
+github.com/vishvananda/netns                        13995c7128ccc8e51e9a6bd2b551020a27180abd
54
+github.com/vishvananda/netlink                      a2ad57a690f3caf3015351d2d6e1c0b95c349752 # v1.0.0
55 55
 
56 56
 # When updating, consider updating TOMLV_COMMIT in hack/dockerfile/install/tomlv.installer accordingly
57 57
 github.com/BurntSushi/toml                          3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005 # v0.3.1
... ...
@@ -12,7 +12,6 @@ import (
12 12
 	"strconv"
13 13
 	"strings"
14 14
 	"sync"
15
-	"syscall"
16 15
 
17 16
 	"github.com/docker/docker/pkg/reexec"
18 17
 	"github.com/docker/libnetwork/datastore"
... ...
@@ -27,6 +26,7 @@ import (
27 27
 	"github.com/vishvananda/netlink"
28 28
 	"github.com/vishvananda/netlink/nl"
29 29
 	"github.com/vishvananda/netns"
30
+	"golang.org/x/sys/unix"
30 31
 )
31 32
 
32 33
 var (
... ...
@@ -97,18 +97,18 @@ func setDefaultVlan() {
97 97
 	}
98 98
 
99 99
 	// make sure the sysfs mount doesn't propagate back
100
-	if err = syscall.Unshare(syscall.CLONE_NEWNS); err != nil {
100
+	if err = unix.Unshare(unix.CLONE_NEWNS); err != nil {
101 101
 		logrus.Errorf("unshare failed, %v", err)
102 102
 		os.Exit(1)
103 103
 	}
104 104
 
105
-	flag := syscall.MS_PRIVATE | syscall.MS_REC
106
-	if err = syscall.Mount("", "/", "", uintptr(flag), ""); err != nil {
105
+	flag := unix.MS_PRIVATE | unix.MS_REC
106
+	if err = unix.Mount("", "/", "", uintptr(flag), ""); err != nil {
107 107
 		logrus.Errorf("root mount failed, %v", err)
108 108
 		os.Exit(1)
109 109
 	}
110 110
 
111
-	if err = syscall.Mount("sysfs", "/sys", "sysfs", 0, ""); err != nil {
111
+	if err = unix.Mount("sysfs", "/sys", "sysfs", 0, ""); err != nil {
112 112
 		logrus.Errorf("mounting sysfs failed, %v", err)
113 113
 		os.Exit(1)
114 114
 	}
... ...
@@ -427,7 +427,7 @@ func populateVNITbl() {
427 427
 			}
428 428
 			defer ns.Close()
429 429
 
430
-			nlh, err := netlink.NewHandleAt(ns, syscall.NETLINK_ROUTE)
430
+			nlh, err := netlink.NewHandleAt(ns, unix.NETLINK_ROUTE)
431 431
 			if err != nil {
432 432
 				logrus.Errorf("Could not open netlink handle during vni population for ns %s: %v", path, err)
433 433
 				return nil
... ...
@@ -583,7 +583,7 @@ func (n *network) setupSubnetSandbox(s *subnet, brName, vxlanName string) error
583 583
 
584 584
 		if ok {
585 585
 			deleteVxlanByVNI(path, s.vni)
586
-			if err := syscall.Unmount(path, syscall.MNT_FORCE); err != nil {
586
+			if err := unix.Unmount(path, unix.MNT_FORCE); err != nil {
587 587
 				logrus.Errorf("unmount of %s failed: %v", path, err)
588 588
 			}
589 589
 			os.Remove(path)
... ...
@@ -693,7 +693,7 @@ func (n *network) cleanupStaleSandboxes() {
693 693
 			if strings.Contains(n.id, pattern) {
694 694
 				// Delete all vnis
695 695
 				deleteVxlanByVNI(path, 0)
696
-				syscall.Unmount(path, syscall.MNT_DETACH)
696
+				unix.Unmount(path, unix.MNT_DETACH)
697 697
 				os.Remove(path)
698 698
 
699 699
 				// Now that we have destroyed this
... ...
@@ -755,12 +755,12 @@ func (n *network) initSandbox(restore bool) error {
755 755
 
756 756
 	var nlSock *nl.NetlinkSocket
757 757
 	sbox.InvokeFunc(func() {
758
-		nlSock, err = nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_NEIGH)
758
+		nlSock, err = nl.Subscribe(unix.NETLINK_ROUTE, unix.RTNLGRP_NEIGH)
759 759
 		if err != nil {
760 760
 			return
761 761
 		}
762 762
 		// set the receive timeout to not remain stuck on the RecvFrom if the fd gets closed
763
-		tv := syscall.NsecToTimeval(soTimeout.Nanoseconds())
763
+		tv := unix.NsecToTimeval(soTimeout.Nanoseconds())
764 764
 		err = nlSock.SetReceiveTimeout(&tv)
765 765
 	})
766 766
 	n.nlSocket = nlSock
... ...
@@ -803,7 +803,7 @@ func (n *network) watchMiss(nlSock *nl.NetlinkSocket, nsPath string) {
803 803
 				return
804 804
 			}
805 805
 			// When the receive timeout expires the receive will return EAGAIN
806
-			if err == syscall.EAGAIN {
806
+			if err == unix.EAGAIN {
807 807
 				// we continue here to avoid spam for timeouts
808 808
 				continue
809 809
 			}
... ...
@@ -812,7 +812,7 @@ func (n *network) watchMiss(nlSock *nl.NetlinkSocket, nsPath string) {
812 812
 		}
813 813
 
814 814
 		for _, msg := range msgs {
815
-			if msg.Header.Type != syscall.RTM_GETNEIGH && msg.Header.Type != syscall.RTM_NEWNEIGH {
815
+			if msg.Header.Type != unix.RTM_GETNEIGH && msg.Header.Type != unix.RTM_NEWNEIGH {
816 816
 				continue
817 817
 			}
818 818
 
... ...
@@ -2,6 +2,7 @@ package libnetwork
2 2
 
3 3
 import (
4 4
 	"github.com/docker/libnetwork/iptables"
5
+	"github.com/docker/libnetwork/netlabel"
5 6
 	"github.com/sirupsen/logrus"
6 7
 )
7 8
 
... ...
@@ -9,15 +10,44 @@ const userChain = "DOCKER-USER"
9 9
 
10 10
 func (c *controller) arrangeUserFilterRule() {
11 11
 	c.Lock()
12
-	arrangeUserFilterRule()
12
+
13
+	if c.hasIPTablesEnabled() {
14
+		arrangeUserFilterRule()
15
+	}
16
+
13 17
 	c.Unlock()
18
+
14 19
 	iptables.OnReloaded(func() {
15 20
 		c.Lock()
16
-		arrangeUserFilterRule()
21
+
22
+		if c.hasIPTablesEnabled() {
23
+			arrangeUserFilterRule()
24
+		}
25
+
17 26
 		c.Unlock()
18 27
 	})
19 28
 }
20 29
 
30
+func (c *controller) hasIPTablesEnabled() bool {
31
+	// Locking c should be handled in the calling method.
32
+	if c.cfg == nil || c.cfg.Daemon.DriverCfg[netlabel.GenericData] == nil {
33
+		return false
34
+	}
35
+
36
+	genericData, ok := c.cfg.Daemon.DriverCfg[netlabel.GenericData]
37
+	if !ok {
38
+		return false
39
+	}
40
+
41
+	optMap := genericData.(map[string]interface{})
42
+	enabled, ok := optMap["EnableIPTables"].(bool)
43
+	if !ok {
44
+		return false
45
+	}
46
+
47
+	return enabled
48
+}
49
+
21 50
 // This chain allow users to configure firewall policies in a way that persists
22 51
 // docker operations/restarts. Docker will not delete or modify any pre-existing
23 52
 // rules from the DOCKER-USER filter chain.
... ...
@@ -3,14 +3,13 @@
3 3
 package ipvs
4 4
 
5 5
 import (
6
+	"fmt"
6 7
 	"net"
7
-	"syscall"
8 8
 	"time"
9 9
 
10
-	"fmt"
11
-
12 10
 	"github.com/vishvananda/netlink/nl"
13 11
 	"github.com/vishvananda/netns"
12
+	"golang.org/x/sys/unix"
14 13
 )
15 14
 
16 15
 const (
... ...
@@ -98,16 +97,16 @@ func New(path string) (*Handle, error) {
98 98
 	}
99 99
 	defer n.Close()
100 100
 
101
-	sock, err := nl.GetNetlinkSocketAt(n, netns.None(), syscall.NETLINK_GENERIC)
101
+	sock, err := nl.GetNetlinkSocketAt(n, netns.None(), unix.NETLINK_GENERIC)
102 102
 	if err != nil {
103 103
 		return nil, err
104 104
 	}
105 105
 	// Add operation timeout to avoid deadlocks
106
-	tv := syscall.NsecToTimeval(netlinkSendSocketTimeout.Nanoseconds())
106
+	tv := unix.NsecToTimeval(netlinkSendSocketTimeout.Nanoseconds())
107 107
 	if err := sock.SetSendTimeout(&tv); err != nil {
108 108
 		return nil, err
109 109
 	}
110
-	tv = syscall.NsecToTimeval(netlinkRecvSocketsTimeout.Nanoseconds())
110
+	tv = unix.NsecToTimeval(netlinkRecvSocketsTimeout.Nanoseconds())
111 111
 	if err := sock.SetReceiveTimeout(&tv); err != nil {
112 112
 		return nil, err
113 113
 	}
... ...
@@ -1381,14 +1381,18 @@ func delIPToName(ipMap setmatrix.SetMatrix, name, serviceID string, ip net.IP) {
1381 1381
 }
1382 1382
 
1383 1383
 func addNameToIP(svcMap setmatrix.SetMatrix, name, serviceID string, epIP net.IP) {
1384
-	svcMap.Insert(name, svcMapEntry{
1384
+	// Since DNS name resolution is case-insensitive, Use the lower-case form
1385
+	// of the name as the key into svcMap
1386
+	lowerCaseName := strings.ToLower(name)
1387
+	svcMap.Insert(lowerCaseName, svcMapEntry{
1385 1388
 		ip:        epIP.String(),
1386 1389
 		serviceID: serviceID,
1387 1390
 	})
1388 1391
 }
1389 1392
 
1390 1393
 func delNameToIP(svcMap setmatrix.SetMatrix, name, serviceID string, epIP net.IP) {
1391
-	svcMap.Remove(name, svcMapEntry{
1394
+	lowerCaseName := strings.ToLower(name)
1395
+	svcMap.Remove(lowerCaseName, svcMapEntry{
1392 1396
 		ip:        epIP.String(),
1393 1397
 		serviceID: serviceID,
1394 1398
 	})
... ...
@@ -1956,6 +1960,7 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
1956 1956
 	}
1957 1957
 
1958 1958
 	req = strings.TrimSuffix(req, ".")
1959
+	req = strings.ToLower(req)
1959 1960
 	ipSet, ok := sr.svcMap.Get(req)
1960 1961
 
1961 1962
 	if ipType == types.IPv6 {
... ...
@@ -366,8 +366,8 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
366 366
 	if query == nil || len(query.Question) == 0 {
367 367
 		return
368 368
 	}
369
-	name := query.Question[0].Name
370 369
 
370
+	name := query.Question[0].Name
371 371
 	switch query.Question[0].Qtype {
372 372
 	case dns.TypeA:
373 373
 		resp, err = r.handleIPQuery(name, query, types.IPv4)
... ...
@@ -1,50 +1,54 @@
1
-github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
2
-github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
3
-github.com/Microsoft/go-winio v0.4.11
4
-github.com/Microsoft/hcsshim v0.7.3
5
-github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
6
-github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
7
-github.com/codegangsta/cli a65b733b303f0055f8d324d805f393cd3e7a7904
8
-github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b
9
-github.com/coreos/etcd v3.2.1
10
-github.com/coreos/go-semver v0.2.0
11
-github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
12
-go.etcd.io/bbolt v1.3.1-etcd.8
1
+github.com/Azure/go-ansiterm            d6e3b3328b783f23731bc4d058875b0371ff8109
2
+github.com/BurntSushi/toml              3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005 # v0.3.1
3
+github.com/Microsoft/go-winio           c599b533b43b1363d7d7c6cfda5ede70ed73ff13
4
+github.com/Microsoft/hcsshim            ba3d6667710fa905116f39a19d059c4c1016be7c
5
+github.com/armon/go-metrics             eb0af217e5e9747e41dd5303755356b62d28e3ec
6
+github.com/armon/go-radix               e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
7
+github.com/codegangsta/cli              a65b733b303f0055f8d324d805f393cd3e7a7904
8
+github.com/containerd/continuity        004b46473808b3e7a4a3049c20e4376c91eb966d
9
+github.com/coreos/etcd                  fca8add78a9d926166eb739b8e4a124434025ba3 # v3.3.9
10
+github.com/coreos/go-semver             8ab6407b697782a06568d4b7f1db25550ec2e4c6 # v0.2.0
11
+github.com/deckarep/golang-set          ef32fa3046d9f249d399f98ebaf9be944430fd1d
12
+go.etcd.io/bbolt                        7ee3ded59d4835e10f3e7d0f7603c42aa5e83820 # v1.3.1-etcd.8
13 13
 
14
-github.com/docker/docker 162ba6016def672690ee4a1f3978368853a1e149
15
-github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
16
-github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
17
-github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
18
-github.com/docker/libkv 458977154600b9f23984d9f4b82e79570b5ae12b
14
+github.com/docker/docker                dbe4a30928d418e0570891a09703bcbc0e4997a1
15
+github.com/docker/distribution          0d3efadf0154c2b8a4e7b6621fff9809655cc580
16
+github.com/docker/go-connections        7395e3f8aa162843a74ed6d48e79627d9792ac55 # v0.4.0
17
+github.com/docker/go-events             9461782956ad83b30282bf90e31fa6a70c255ba9
18
+github.com/docker/go-units              47565b4f722fb6ceae66b95f853feed578a4a51c # v0.3.3
19
+github.com/docker/libkv                 458977154600b9f23984d9f4b82e79570b5ae12b
19 20
 
20
-github.com/godbus/dbus v4.0.0
21
-github.com/gogo/protobuf v1.0.0
22
-github.com/gorilla/context v1.1
23
-github.com/gorilla/mux v1.1
24
-github.com/hashicorp/consul v0.5.2
25
-github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
26
-github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e
27
-github.com/hashicorp/memberlist 3d8438da9589e7b608a83ffac1ef8211486bcb7c
28
-github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372
29
-github.com/hashicorp/go-sockaddr 6d291a969b86c4b633730bfc6b8b9d64c3aafed9
30
-github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
31
-github.com/mattn/go-shellwords v1.0.3
32
-github.com/miekg/dns v1.0.7
33
-github.com/opencontainers/go-digest v1.0.0-rc1
34
-github.com/opencontainers/image-spec v1.0.1
35
-github.com/opencontainers/runc 96ec2177ae841256168fcf76954f7177af9446eb
36
-github.com/opencontainers/runtime-spec v1.0.1
37
-github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
38
-github.com/sirupsen/logrus v1.0.3
39
-github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
40
-github.com/vishvananda/netlink b2de5d10e38ecce8607e6b438b6d174f389a004e
41
-github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
42
-golang.org/x/crypto 1a580b3eff7814fc9b40602fd35256c63b50f491
43
-golang.org/x/net 0ed95abb35c445290478a5348a7b38bb154135fd
44
-golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd
45
-golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
46
-github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
47
-github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb
21
+github.com/gogo/protobuf                ba06b47c162d49f2af050fb4c75bcbc86a159d5c # v1.2.1
22
+github.com/golang/protobuf              aa810b61a9c79d51363740d207bb46cf8e620ed5 # v1.2.0
23
+google.golang.org/grpc                  7a6a684ca69eb4cae85ad0a484f2e531598c047b # v1.12.2
24
+google.golang.org/genproto              694d95ba50e67b2e363f3483057db5d4910c18f9
48 25
 
49
-gotest.tools v2.1.0
50
-github.com/google/go-cmp v0.2.0
26
+github.com/godbus/dbus                  5f6efc7ef2759c81b7ba876593971bfce311eab3 # v4.0.0
27
+github.com/gorilla/mux                  c5c6c98bc25355028a63748a498942a6398ccd22 # v1.7.1
28
+github.com/hashicorp/consul             9a9cc9341bb487651a0399e3fc5e1e8a42e62dd9 # v0.5.2
29
+github.com/hashicorp/go-msgpack         71c2886f5a673a35f909803f38ece5810165097b
30
+github.com/hashicorp/go-multierror      fcdddc395df1ddf4247c69bd436e84cfa0733f7e
31
+github.com/hashicorp/memberlist         3d8438da9589e7b608a83ffac1ef8211486bcb7c
32
+github.com/sean-/seed                   e2103e2c35297fb7e17febb81e49b312087a2372
33
+github.com/hashicorp/go-sockaddr        6d291a969b86c4b633730bfc6b8b9d64c3aafed9
34
+github.com/hashicorp/serf               598c54895cc5a7b1a24a398d635e8c0ea0959870
35
+github.com/mattn/go-shellwords          02e3cf038dcea8290e44424da473dd12be796a8a # v1.0.3
36
+github.com/miekg/dns                    e57bf427e68187a27e22adceac868350d7a7079b # v1.0.7
37
+github.com/opencontainers/go-digest     279bed98673dd5bef374d3b6e4b09e2af76183bf # v1.0.0-rc1
38
+github.com/opencontainers/image-spec    d60099175f88c47cd379c4738d158884749ed235 # v1.0.1
39
+github.com/opencontainers/runc          2b18fe1d885ee5083ef9f0838fee39b62d653e30
40
+github.com/opencontainers/runtime-spec  29686dbc5559d93fb1ef402eeda3e35c38d75af4 # v1.0.1-59-g29686db
41
+github.com/samuel/go-zookeeper          d0e0d8e11f318e000a8cc434616d69e329edc374
42
+github.com/sirupsen/logrus              f006c2ac4710855cf0f916dd6b77acf6b048dc6e # v1.0.3
43
+github.com/ugorji/go                    b4c50a2b199d93b13dc15e78929cfb23bfdf21ab # v1.1.1
44
+github.com/vishvananda/netlink          a2ad57a690f3caf3015351d2d6e1c0b95c349752 # v1.0.0
45
+github.com/vishvananda/netns            13995c7128ccc8e51e9a6bd2b551020a27180abd
46
+golang.org/x/crypto                     b7391e95e576cacdcdd422573063bc057239113d
47
+golang.org/x/net                        a680a1efc54dd51c040b3b5ce4939ea3cf2ea0d1
48
+golang.org/x/sys                        d455e41777fca6e8a5a79e34a14b8368bc11d9ba
49
+golang.org/x/sync                       1d60e4601c6fd243af51cc01ddf169918a5407ca
50
+github.com/pkg/errors                   ba968bfe8b2f7e042a574c888954fccecfa385b4 # v0.8.1
51
+github.com/ishidawataru/sctp            07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb
52
+
53
+gotest.tools                            b6e20af1ed078cd01a6413b734051a292450b4cb # v2.1.0
54
+github.com/google/go-cmp                3af367b6b30c263d47e8895973edcca9a49cf029 # v0.2.0
... ...
@@ -89,3 +89,4 @@ There are also a few pieces of low level netlink functionality that still
89 89
 need to be implemented. Routing rules are not in place and some of the
90 90
 more advanced link types. Hopefully there is decent structure and testing
91 91
 in place to make these fairly straightforward to add.
92
+
... ...
@@ -8,6 +8,7 @@ import (
8 8
 
9 9
 	"github.com/vishvananda/netlink/nl"
10 10
 	"github.com/vishvananda/netns"
11
+	"golang.org/x/sys/unix"
11 12
 )
12 13
 
13 14
 // IFA_FLAGS is a u32 attribute.
... ...
@@ -22,7 +23,7 @@ func AddrAdd(link Link, addr *Addr) error {
22 22
 // AddrAdd will add an IP address to a link device.
23 23
 // Equivalent to: `ip addr add $addr dev $link`
24 24
 func (h *Handle) AddrAdd(link Link, addr *Addr) error {
25
-	req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
25
+	req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
26 26
 	return h.addrHandle(link, addr, req)
27 27
 }
28 28
 
... ...
@@ -35,7 +36,7 @@ func AddrReplace(link Link, addr *Addr) error {
35 35
 // AddrReplace will replace (or, if not present, add) an IP address on a link device.
36 36
 // Equivalent to: `ip addr replace $addr dev $link`
37 37
 func (h *Handle) AddrReplace(link Link, addr *Addr) error {
38
-	req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE|syscall.NLM_F_ACK)
38
+	req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_REPLACE|unix.NLM_F_ACK)
39 39
 	return h.addrHandle(link, addr, req)
40 40
 }
41 41
 
... ...
@@ -48,7 +49,7 @@ func AddrDel(link Link, addr *Addr) error {
48 48
 // AddrDel will delete an IP address from a link device.
49 49
 // Equivalent to: `ip addr del $addr dev $link`
50 50
 func (h *Handle) AddrDel(link Link, addr *Addr) error {
51
-	req := h.newNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK)
51
+	req := h.newNetlinkRequest(unix.RTM_DELADDR, unix.NLM_F_ACK)
52 52
 	return h.addrHandle(link, addr, req)
53 53
 }
54 54
 
... ...
@@ -75,7 +76,7 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
75 75
 		localAddrData = addr.IP.To16()
76 76
 	}
77 77
 
78
-	localData := nl.NewRtAttr(syscall.IFA_LOCAL, localAddrData)
78
+	localData := nl.NewRtAttr(unix.IFA_LOCAL, localAddrData)
79 79
 	req.AddData(localData)
80 80
 	var peerAddrData []byte
81 81
 	if addr.Peer != nil {
... ...
@@ -88,7 +89,7 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
88 88
 		peerAddrData = localAddrData
89 89
 	}
90 90
 
91
-	addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, peerAddrData)
91
+	addressData := nl.NewRtAttr(unix.IFA_ADDRESS, peerAddrData)
92 92
 	req.AddData(addressData)
93 93
 
94 94
 	if addr.Flags != 0 {
... ...
@@ -102,21 +103,34 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
102 102
 		}
103 103
 	}
104 104
 
105
-	if addr.Broadcast == nil {
106
-		calcBroadcast := make(net.IP, masklen/8)
107
-		for i := range localAddrData {
108
-			calcBroadcast[i] = localAddrData[i] | ^addr.Mask[i]
105
+	if family == FAMILY_V4 {
106
+		if addr.Broadcast == nil {
107
+			calcBroadcast := make(net.IP, masklen/8)
108
+			for i := range localAddrData {
109
+				calcBroadcast[i] = localAddrData[i] | ^addr.Mask[i]
110
+			}
111
+			addr.Broadcast = calcBroadcast
112
+		}
113
+		req.AddData(nl.NewRtAttr(unix.IFA_BROADCAST, addr.Broadcast))
114
+
115
+		if addr.Label != "" {
116
+			labelData := nl.NewRtAttr(unix.IFA_LABEL, nl.ZeroTerminated(addr.Label))
117
+			req.AddData(labelData)
109 118
 		}
110
-		addr.Broadcast = calcBroadcast
111 119
 	}
112
-	req.AddData(nl.NewRtAttr(syscall.IFA_BROADCAST, addr.Broadcast))
113 120
 
114
-	if addr.Label != "" {
115
-		labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label))
116
-		req.AddData(labelData)
121
+	// 0 is the default value for these attributes. However, 0 means "expired", while the least-surprising default
122
+	// value should be "forever". To compensate for that, only add the attributes if at least one of the values is
123
+	// non-zero, which means the caller has explicitly set them
124
+	if addr.ValidLft > 0 || addr.PreferedLft > 0 {
125
+		cachedata := nl.IfaCacheInfo{
126
+			IfaValid:    uint32(addr.ValidLft),
127
+			IfaPrefered: uint32(addr.PreferedLft),
128
+		}
129
+		req.AddData(nl.NewRtAttr(unix.IFA_CACHEINFO, cachedata.Serialize()))
117 130
 	}
118 131
 
119
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
132
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
120 133
 	return err
121 134
 }
122 135
 
... ...
@@ -131,11 +145,11 @@ func AddrList(link Link, family int) ([]Addr, error) {
131 131
 // Equivalent to: `ip addr show`.
132 132
 // The list can be filtered by link and ip family.
133 133
 func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
134
-	req := h.newNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
134
+	req := h.newNetlinkRequest(unix.RTM_GETADDR, unix.NLM_F_DUMP)
135 135
 	msg := nl.NewIfInfomsg(family)
136 136
 	req.AddData(msg)
137 137
 
138
-	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR)
138
+	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
139 139
 	if err != nil {
140 140
 		return nil, err
141 141
 	}
... ...
@@ -187,21 +201,21 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
187 187
 	var local, dst *net.IPNet
188 188
 	for _, attr := range attrs {
189 189
 		switch attr.Attr.Type {
190
-		case syscall.IFA_ADDRESS:
190
+		case unix.IFA_ADDRESS:
191 191
 			dst = &net.IPNet{
192 192
 				IP:   attr.Value,
193 193
 				Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
194 194
 			}
195 195
 			addr.Peer = dst
196
-		case syscall.IFA_LOCAL:
196
+		case unix.IFA_LOCAL:
197 197
 			local = &net.IPNet{
198 198
 				IP:   attr.Value,
199 199
 				Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
200 200
 			}
201 201
 			addr.IPNet = local
202
-		case syscall.IFA_BROADCAST:
202
+		case unix.IFA_BROADCAST:
203 203
 			addr.Broadcast = attr.Value
204
-		case syscall.IFA_LABEL:
204
+		case unix.IFA_LABEL:
205 205
 			addr.Label = string(attr.Value[:len(attr.Value)-1])
206 206
 		case IFA_FLAGS:
207 207
 			addr.Flags = int(native.Uint32(attr.Value[0:4]))
... ...
@@ -236,13 +250,13 @@ type AddrUpdate struct {
236 236
 // AddrSubscribe takes a chan down which notifications will be sent
237 237
 // when addresses change.  Close the 'done' chan to stop subscription.
238 238
 func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
239
-	return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil)
239
+	return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
240 240
 }
241 241
 
242 242
 // AddrSubscribeAt works like AddrSubscribe plus it allows the caller
243 243
 // to choose the network namespace in which to subscribe (ns).
244 244
 func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
245
-	return addrSubscribeAt(ns, netns.None(), ch, done, nil)
245
+	return addrSubscribeAt(ns, netns.None(), ch, done, nil, false)
246 246
 }
247 247
 
248 248
 // AddrSubscribeOptions contains a set of options to use with
... ...
@@ -250,6 +264,7 @@ func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct
250 250
 type AddrSubscribeOptions struct {
251 251
 	Namespace     *netns.NsHandle
252 252
 	ErrorCallback func(error)
253
+	ListExisting  bool
253 254
 }
254 255
 
255 256
 // AddrSubscribeWithOptions work like AddrSubscribe but enable to
... ...
@@ -260,11 +275,11 @@ func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, option
260 260
 		none := netns.None()
261 261
 		options.Namespace = &none
262 262
 	}
263
-	return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback)
263
+	return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
264 264
 }
265 265
 
266
-func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error)) error {
267
-	s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR)
266
+func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
267
+	s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_IFADDR, unix.RTNLGRP_IPV6_IFADDR)
268 268
 	if err != nil {
269 269
 		return err
270 270
 	}
... ...
@@ -274,6 +289,15 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
274 274
 			s.Close()
275 275
 		}()
276 276
 	}
277
+	if listExisting {
278
+		req := pkgHandle.newNetlinkRequest(unix.RTM_GETADDR,
279
+			unix.NLM_F_DUMP)
280
+		infmsg := nl.NewIfInfomsg(unix.AF_UNSPEC)
281
+		req.AddData(infmsg)
282
+		if err := s.Send(req); err != nil {
283
+			return err
284
+		}
285
+	}
277 286
 	go func() {
278 287
 		defer close(ch)
279 288
 		for {
... ...
@@ -285,8 +309,22 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
285 285
 				return
286 286
 			}
287 287
 			for _, m := range msgs {
288
+				if m.Header.Type == unix.NLMSG_DONE {
289
+					continue
290
+				}
291
+				if m.Header.Type == unix.NLMSG_ERROR {
292
+					native := nl.NativeEndian()
293
+					error := int32(native.Uint32(m.Data[0:4]))
294
+					if error == 0 {
295
+						continue
296
+					}
297
+					if cberr != nil {
298
+						cberr(syscall.Errno(-error))
299
+					}
300
+					return
301
+				}
288 302
 				msgType := m.Header.Type
289
-				if msgType != syscall.RTM_NEWADDR && msgType != syscall.RTM_DELADDR {
303
+				if msgType != unix.RTM_NEWADDR && msgType != unix.RTM_DELADDR {
290 304
 					if cberr != nil {
291 305
 						cberr(fmt.Errorf("bad message type: %d", msgType))
292 306
 					}
... ...
@@ -303,7 +341,7 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
303 303
 
304 304
 				ch <- AddrUpdate{LinkAddress: *addr.IPNet,
305 305
 					LinkIndex:   ifindex,
306
-					NewAddr:     msgType == syscall.RTM_NEWADDR,
306
+					NewAddr:     msgType == unix.RTM_NEWADDR,
307 307
 					Flags:       addr.Flags,
308 308
 					Scope:       addr.Scope,
309 309
 					PreferedLft: addr.PreferedLft,
... ...
@@ -1,49 +1,12 @@
1 1
 package netlink
2 2
 
3
-/*
4
-#include <asm/types.h>
5
-#include <asm/unistd.h>
6
-#include <errno.h>
7
-#include <stdio.h>
8
-#include <stdint.h>
9
-#include <unistd.h>
3
+import (
4
+	"unsafe"
10 5
 
11
-static int load_simple_bpf(int prog_type, int ret) {
12
-#ifdef __NR_bpf
13
-	// { return ret; }
14
-	__u64 __attribute__((aligned(8))) insns[] = {
15
-		0x00000000000000b7ull | ((__u64)ret<<32),
16
-		0x0000000000000095ull,
17
-	};
18
-	__u8 __attribute__((aligned(8))) license[] = "ASL2";
19
-	// Copied from a header file since libc is notoriously slow to update.
20
-	// The call will succeed or fail and that will be our indication on
21
-	// whether or not it is supported.
22
-	struct {
23
-		__u32 prog_type;
24
-		__u32 insn_cnt;
25
-		__u64 insns;
26
-		__u64 license;
27
-		__u32 log_level;
28
-		__u32 log_size;
29
-		__u64 log_buf;
30
-		__u32 kern_version;
31
-	} __attribute__((aligned(8))) attr = {
32
-		.prog_type = prog_type,
33
-		.insn_cnt = 2,
34
-		.insns = (uintptr_t)&insns,
35
-		.license = (uintptr_t)&license,
36
-	};
37
-	return syscall(__NR_bpf, 5, &attr, sizeof(attr));
38
-#else
39
-	errno = EINVAL;
40
-	return -1;
41
-#endif
42
-}
43
-*/
44
-import "C"
6
+	"golang.org/x/sys/unix"
7
+)
45 8
 
46
-type BpfProgType C.int
9
+type BpfProgType uint32
47 10
 
48 11
 const (
49 12
 	BPF_PROG_TYPE_UNSPEC BpfProgType = iota
... ...
@@ -55,8 +18,36 @@ const (
55 55
 	BPF_PROG_TYPE_XDP
56 56
 )
57 57
 
58
-// loadSimpleBpf loads a trivial bpf program for testing purposes
59
-func loadSimpleBpf(progType BpfProgType, ret int) (int, error) {
60
-	fd, err := C.load_simple_bpf(C.int(progType), C.int(ret))
61
-	return int(fd), err
58
+type BPFAttr struct {
59
+	ProgType    uint32
60
+	InsnCnt     uint32
61
+	Insns       uintptr
62
+	License     uintptr
63
+	LogLevel    uint32
64
+	LogSize     uint32
65
+	LogBuf      uintptr
66
+	KernVersion uint32
67
+}
68
+
69
+// loadSimpleBpf loads a trivial bpf program for testing purposes.
70
+func loadSimpleBpf(progType BpfProgType, ret uint32) (int, error) {
71
+	insns := []uint64{
72
+		0x00000000000000b7 | (uint64(ret) << 32),
73
+		0x0000000000000095,
74
+	}
75
+	license := []byte{'A', 'S', 'L', '2', '\x00'}
76
+	attr := BPFAttr{
77
+		ProgType: uint32(progType),
78
+		InsnCnt:  uint32(len(insns)),
79
+		Insns:    uintptr(unsafe.Pointer(&insns[0])),
80
+		License:  uintptr(unsafe.Pointer(&license[0])),
81
+	}
82
+	fd, _, errno := unix.Syscall(unix.SYS_BPF,
83
+		5, /* bpf cmd */
84
+		uintptr(unsafe.Pointer(&attr)),
85
+		unsafe.Sizeof(attr))
86
+	if errno != 0 {
87
+		return 0, errno
88
+	}
89
+	return int(fd), nil
62 90
 }
... ...
@@ -2,9 +2,9 @@ package netlink
2 2
 
3 3
 import (
4 4
 	"fmt"
5
-	"syscall"
6 5
 
7 6
 	"github.com/vishvananda/netlink/nl"
7
+	"golang.org/x/sys/unix"
8 8
 )
9 9
 
10 10
 // BridgeVlanList gets a map of device id to bridge vlan infos.
... ...
@@ -16,12 +16,12 @@ func BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
16 16
 // BridgeVlanList gets a map of device id to bridge vlan infos.
17 17
 // Equivalent to: `bridge vlan show`
18 18
 func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
19
-	req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP)
20
-	msg := nl.NewIfInfomsg(syscall.AF_BRIDGE)
19
+	req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
20
+	msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
21 21
 	req.AddData(msg)
22
-	req.AddData(nl.NewRtAttr(nl.IFLA_EXT_MASK, nl.Uint32Attr(uint32(nl.RTEXT_FILTER_BRVLAN))))
22
+	req.AddData(nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(uint32(nl.RTEXT_FILTER_BRVLAN))))
23 23
 
24
-	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWLINK)
24
+	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
25 25
 	if err != nil {
26 26
 		return nil, err
27 27
 	}
... ...
@@ -35,7 +35,7 @@ func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
35 35
 		}
36 36
 		for _, attr := range attrs {
37 37
 			switch attr.Attr.Type {
38
-			case nl.IFLA_AF_SPEC:
38
+			case unix.IFLA_AF_SPEC:
39 39
 				//nested attr
40 40
 				nestAttrs, err := nl.ParseRouteAttr(attr.Value)
41 41
 				if err != nil {
... ...
@@ -63,7 +63,7 @@ func BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) err
63 63
 // BridgeVlanAdd adds a new vlan filter entry
64 64
 // Equivalent to: `bridge vlan add dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
65 65
 func (h *Handle) BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) error {
66
-	return h.bridgeVlanModify(syscall.RTM_SETLINK, link, vid, pvid, untagged, self, master)
66
+	return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, pvid, untagged, self, master)
67 67
 }
68 68
 
69 69
 // BridgeVlanDel adds a new vlan filter entry
... ...
@@ -75,19 +75,19 @@ func BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) err
75 75
 // BridgeVlanDel adds a new vlan filter entry
76 76
 // Equivalent to: `bridge vlan del dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
77 77
 func (h *Handle) BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) error {
78
-	return h.bridgeVlanModify(syscall.RTM_DELLINK, link, vid, pvid, untagged, self, master)
78
+	return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, pvid, untagged, self, master)
79 79
 }
80 80
 
81 81
 func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged, self, master bool) error {
82 82
 	base := link.Attrs()
83 83
 	h.ensureIndex(base)
84
-	req := h.newNetlinkRequest(cmd, syscall.NLM_F_ACK)
84
+	req := h.newNetlinkRequest(cmd, unix.NLM_F_ACK)
85 85
 
86
-	msg := nl.NewIfInfomsg(syscall.AF_BRIDGE)
86
+	msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
87 87
 	msg.Index = int32(base.Index)
88 88
 	req.AddData(msg)
89 89
 
90
-	br := nl.NewRtAttr(nl.IFLA_AF_SPEC, nil)
90
+	br := nl.NewRtAttr(unix.IFLA_AF_SPEC, nil)
91 91
 	var flags uint16
92 92
 	if self {
93 93
 		flags |= nl.BRIDGE_FLAGS_SELF
... ...
@@ -107,7 +107,7 @@ func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged
107 107
 	}
108 108
 	nl.NewRtAttrChild(br, nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
109 109
 	req.AddData(br)
110
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
110
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
111 111
 	if err != nil {
112 112
 		return err
113 113
 	}
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"syscall"
6 6
 
7 7
 	"github.com/vishvananda/netlink/nl"
8
+	"golang.org/x/sys/unix"
8 9
 )
9 10
 
10 11
 // NOTE: function is in here because it uses other linux functions
... ...
@@ -50,7 +51,7 @@ func ClassDel(class Class) error {
50 50
 // ClassDel will delete a class from the system.
51 51
 // Equivalent to: `tc class del $class`
52 52
 func (h *Handle) ClassDel(class Class) error {
53
-	return h.classModify(syscall.RTM_DELTCLASS, 0, class)
53
+	return h.classModify(unix.RTM_DELTCLASS, 0, class)
54 54
 }
55 55
 
56 56
 // ClassChange will change a class in place
... ...
@@ -64,7 +65,7 @@ func ClassChange(class Class) error {
64 64
 // Equivalent to: `tc class change $class`
65 65
 // The parent and handle MUST NOT be changed.
66 66
 func (h *Handle) ClassChange(class Class) error {
67
-	return h.classModify(syscall.RTM_NEWTCLASS, 0, class)
67
+	return h.classModify(unix.RTM_NEWTCLASS, 0, class)
68 68
 }
69 69
 
70 70
 // ClassReplace will replace a class to the system.
... ...
@@ -82,7 +83,7 @@ func ClassReplace(class Class) error {
82 82
 // If a class already exist with this parent/handle pair, the class is changed.
83 83
 // If a class does not already exist with this parent/handle, a new class is created.
84 84
 func (h *Handle) ClassReplace(class Class) error {
85
-	return h.classModify(syscall.RTM_NEWTCLASS, syscall.NLM_F_CREATE, class)
85
+	return h.classModify(unix.RTM_NEWTCLASS, unix.NLM_F_CREATE, class)
86 86
 }
87 87
 
88 88
 // ClassAdd will add a class to the system.
... ...
@@ -95,14 +96,14 @@ func ClassAdd(class Class) error {
95 95
 // Equivalent to: `tc class add $class`
96 96
 func (h *Handle) ClassAdd(class Class) error {
97 97
 	return h.classModify(
98
-		syscall.RTM_NEWTCLASS,
99
-		syscall.NLM_F_CREATE|syscall.NLM_F_EXCL,
98
+		unix.RTM_NEWTCLASS,
99
+		unix.NLM_F_CREATE|unix.NLM_F_EXCL,
100 100
 		class,
101 101
 	)
102 102
 }
103 103
 
104 104
 func (h *Handle) classModify(cmd, flags int, class Class) error {
105
-	req := h.newNetlinkRequest(cmd, flags|syscall.NLM_F_ACK)
105
+	req := h.newNetlinkRequest(cmd, flags|unix.NLM_F_ACK)
106 106
 	base := class.Attrs()
107 107
 	msg := &nl.TcMsg{
108 108
 		Family:  nl.FAMILY_ALL,
... ...
@@ -112,12 +113,12 @@ func (h *Handle) classModify(cmd, flags int, class Class) error {
112 112
 	}
113 113
 	req.AddData(msg)
114 114
 
115
-	if cmd != syscall.RTM_DELTCLASS {
115
+	if cmd != unix.RTM_DELTCLASS {
116 116
 		if err := classPayload(req, class); err != nil {
117 117
 			return err
118 118
 		}
119 119
 	}
120
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
120
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
121 121
 	return err
122 122
 }
123 123
 
... ...
@@ -141,12 +142,12 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
141 141
 		var rtab [256]uint32
142 142
 		var ctab [256]uint32
143 143
 		tcrate := nl.TcRateSpec{Rate: uint32(htb.Rate)}
144
-		if CalcRtable(&tcrate, rtab, cellLog, uint32(mtu), linklayer) < 0 {
144
+		if CalcRtable(&tcrate, rtab[:], cellLog, uint32(mtu), linklayer) < 0 {
145 145
 			return errors.New("HTB: failed to calculate rate table")
146 146
 		}
147 147
 		opt.Rate = tcrate
148 148
 		tcceil := nl.TcRateSpec{Rate: uint32(htb.Ceil)}
149
-		if CalcRtable(&tcceil, ctab, ccellLog, uint32(mtu), linklayer) < 0 {
149
+		if CalcRtable(&tcceil, ctab[:], ccellLog, uint32(mtu), linklayer) < 0 {
150 150
 			return errors.New("HTB: failed to calculate ceil rate table")
151 151
 		}
152 152
 		opt.Ceil = tcceil
... ...
@@ -169,7 +170,7 @@ func ClassList(link Link, parent uint32) ([]Class, error) {
169 169
 // Equivalent to: `tc class show`.
170 170
 // Generally returns nothing if link and parent are not specified.
171 171
 func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
172
-	req := h.newNetlinkRequest(syscall.RTM_GETTCLASS, syscall.NLM_F_DUMP)
172
+	req := h.newNetlinkRequest(unix.RTM_GETTCLASS, unix.NLM_F_DUMP)
173 173
 	msg := &nl.TcMsg{
174 174
 		Family: nl.FAMILY_ALL,
175 175
 		Parent: parent,
... ...
@@ -181,7 +182,7 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
181 181
 	}
182 182
 	req.AddData(msg)
183 183
 
184
-	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWTCLASS)
184
+	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTCLASS)
185 185
 	if err != nil {
186 186
 		return nil, err
187 187
 	}
... ...
@@ -6,9 +6,9 @@ import (
6 6
 	"errors"
7 7
 	"fmt"
8 8
 	"net"
9
-	"syscall"
10 9
 
11 10
 	"github.com/vishvananda/netlink/nl"
11
+	"golang.org/x/sys/unix"
12 12
 )
13 13
 
14 14
 // ConntrackTableType Conntrack table for the netlink operation
... ...
@@ -85,8 +85,8 @@ func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily)
85 85
 // conntrack -F [table]            Flush table
86 86
 // The flush operation applies to all the family types
87 87
 func (h *Handle) ConntrackTableFlush(table ConntrackTableType) error {
88
-	req := h.newConntrackRequest(table, syscall.AF_INET, nl.IPCTNL_MSG_CT_DELETE, syscall.NLM_F_ACK)
89
-	_, err := req.Execute(syscall.NETLINK_NETFILTER, 0)
88
+	req := h.newConntrackRequest(table, unix.AF_INET, nl.IPCTNL_MSG_CT_DELETE, unix.NLM_F_ACK)
89
+	_, err := req.Execute(unix.NETLINK_NETFILTER, 0)
90 90
 	return err
91 91
 }
92 92
 
... ...
@@ -102,10 +102,10 @@ func (h *Handle) ConntrackDeleteFilter(table ConntrackTableType, family InetFami
102 102
 	for _, dataRaw := range res {
103 103
 		flow := parseRawData(dataRaw)
104 104
 		if match := filter.MatchConntrackFlow(flow); match {
105
-			req2 := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_DELETE, syscall.NLM_F_ACK)
105
+			req2 := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_DELETE, unix.NLM_F_ACK)
106 106
 			// skip the first 4 byte that are the netfilter header, the newConntrackRequest is adding it already
107 107
 			req2.AddRawData(dataRaw[4:])
108
-			req2.Execute(syscall.NETLINK_NETFILTER, 0)
108
+			req2.Execute(unix.NETLINK_NETFILTER, 0)
109 109
 			matched++
110 110
 		}
111 111
 	}
... ...
@@ -127,8 +127,8 @@ func (h *Handle) newConntrackRequest(table ConntrackTableType, family InetFamily
127 127
 }
128 128
 
129 129
 func (h *Handle) dumpConntrackTable(table ConntrackTableType, family InetFamily) ([][]byte, error) {
130
-	req := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_GET, syscall.NLM_F_DUMP)
131
-	return req.Execute(syscall.NETLINK_NETFILTER, 0)
130
+	req := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_GET, unix.NLM_F_DUMP)
131
+	return req.Execute(unix.NETLINK_NETFILTER, 0)
132 132
 }
133 133
 
134 134
 // The full conntrack flow structure is very complicated and can be found in the file:
... ...
@@ -17,7 +17,7 @@ type FilterAttrs struct {
17 17
 	Handle    uint32
18 18
 	Parent    uint32
19 19
 	Priority  uint16 // lower is higher priority
20
-	Protocol  uint16 // syscall.ETH_P_*
20
+	Protocol  uint16 // unix.ETH_P_*
21 21
 }
22 22
 
23 23
 func (q FilterAttrs) String() string {
... ...
@@ -225,6 +225,21 @@ func (filter *U32) Type() string {
225 225
 	return "u32"
226 226
 }
227 227
 
228
+// MatchAll filters match all packets
229
+type MatchAll struct {
230
+	FilterAttrs
231
+	ClassId uint32
232
+	Actions []Action
233
+}
234
+
235
+func (filter *MatchAll) Attrs() *FilterAttrs {
236
+	return &filter.FilterAttrs
237
+}
238
+
239
+func (filter *MatchAll) Type() string {
240
+	return "matchall"
241
+}
242
+
228 243
 type FilterFwAttrs struct {
229 244
 	ClassId   uint32
230 245
 	InDev     string
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"unsafe"
10 10
 
11 11
 	"github.com/vishvananda/netlink/nl"
12
+	"golang.org/x/sys/unix"
12 13
 )
13 14
 
14 15
 // Constants used in TcU32Sel.Flags.
... ...
@@ -55,7 +56,7 @@ func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) {
55 55
 	if police.Rate.Rate != 0 {
56 56
 		police.Rate.Mpu = fattrs.Mpu
57 57
 		police.Rate.Overhead = fattrs.Overhead
58
-		if CalcRtable(&police.Rate, rtab, rcellLog, fattrs.Mtu, linklayer) < 0 {
58
+		if CalcRtable(&police.Rate, rtab[:], rcellLog, fattrs.Mtu, linklayer) < 0 {
59 59
 			return nil, errors.New("TBF: failed to calculate rate table")
60 60
 		}
61 61
 		police.Burst = uint32(Xmittime(uint64(police.Rate.Rate), uint32(buffer)))
... ...
@@ -64,7 +65,7 @@ func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) {
64 64
 	if police.PeakRate.Rate != 0 {
65 65
 		police.PeakRate.Mpu = fattrs.Mpu
66 66
 		police.PeakRate.Overhead = fattrs.Overhead
67
-		if CalcRtable(&police.PeakRate, ptab, pcellLog, fattrs.Mtu, linklayer) < 0 {
67
+		if CalcRtable(&police.PeakRate, ptab[:], pcellLog, fattrs.Mtu, linklayer) < 0 {
68 68
 			return nil, errors.New("POLICE: failed to calculate peak rate table")
69 69
 		}
70 70
 	}
... ...
@@ -98,7 +99,7 @@ func FilterDel(filter Filter) error {
98 98
 // FilterDel will delete a filter from the system.
99 99
 // Equivalent to: `tc filter del $filter`
100 100
 func (h *Handle) FilterDel(filter Filter) error {
101
-	req := h.newNetlinkRequest(syscall.RTM_DELTFILTER, syscall.NLM_F_ACK)
101
+	req := h.newNetlinkRequest(unix.RTM_DELTFILTER, unix.NLM_F_ACK)
102 102
 	base := filter.Attrs()
103 103
 	msg := &nl.TcMsg{
104 104
 		Family:  nl.FAMILY_ALL,
... ...
@@ -109,7 +110,7 @@ func (h *Handle) FilterDel(filter Filter) error {
109 109
 	}
110 110
 	req.AddData(msg)
111 111
 
112
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
112
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
113 113
 	return err
114 114
 }
115 115
 
... ...
@@ -123,7 +124,7 @@ func FilterAdd(filter Filter) error {
123 123
 // Equivalent to: `tc filter add $filter`
124 124
 func (h *Handle) FilterAdd(filter Filter) error {
125 125
 	native = nl.NativeEndian()
126
-	req := h.newNetlinkRequest(syscall.RTM_NEWTFILTER, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
126
+	req := h.newNetlinkRequest(unix.RTM_NEWTFILTER, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
127 127
 	base := filter.Attrs()
128 128
 	msg := &nl.TcMsg{
129 129
 		Family:  nl.FAMILY_ALL,
... ...
@@ -221,10 +222,18 @@ func (h *Handle) FilterAdd(filter Filter) error {
221 221
 			bpfFlags |= nl.TCA_BPF_FLAG_ACT_DIRECT
222 222
 		}
223 223
 		nl.NewRtAttrChild(options, nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags))
224
+	case *MatchAll:
225
+		actionsAttr := nl.NewRtAttrChild(options, nl.TCA_MATCHALL_ACT, nil)
226
+		if err := EncodeActions(actionsAttr, filter.Actions); err != nil {
227
+			return err
228
+		}
229
+		if filter.ClassId != 0 {
230
+			nl.NewRtAttrChild(options, nl.TCA_MATCHALL_CLASSID, nl.Uint32Attr(filter.ClassId))
231
+		}
224 232
 	}
225 233
 
226 234
 	req.AddData(options)
227
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
235
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
228 236
 	return err
229 237
 }
230 238
 
... ...
@@ -239,7 +248,7 @@ func FilterList(link Link, parent uint32) ([]Filter, error) {
239 239
 // Equivalent to: `tc filter show`.
240 240
 // Generally returns nothing if link and parent are not specified.
241 241
 func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
242
-	req := h.newNetlinkRequest(syscall.RTM_GETTFILTER, syscall.NLM_F_DUMP)
242
+	req := h.newNetlinkRequest(unix.RTM_GETTFILTER, unix.NLM_F_DUMP)
243 243
 	msg := &nl.TcMsg{
244 244
 		Family: nl.FAMILY_ALL,
245 245
 		Parent: parent,
... ...
@@ -251,7 +260,7 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
251 251
 	}
252 252
 	req.AddData(msg)
253 253
 
254
-	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWTFILTER)
254
+	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTFILTER)
255 255
 	if err != nil {
256 256
 		return nil, err
257 257
 	}
... ...
@@ -287,6 +296,8 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
287 287
 					filter = &Fw{}
288 288
 				case "bpf":
289 289
 					filter = &BpfFilter{}
290
+				case "matchall":
291
+					filter = &MatchAll{}
290 292
 				default:
291 293
 					filter = &GenericFilter{FilterType: filterType}
292 294
 				}
... ...
@@ -311,6 +322,11 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
311 311
 					if err != nil {
312 312
 						return nil, err
313 313
 					}
314
+				case "matchall":
315
+					detailed, err = parseMatchAllData(filter, data)
316
+					if err != nil {
317
+						return nil, err
318
+					}
314 319
 				default:
315 320
 					detailed = true
316 321
 				}
... ...
@@ -540,6 +556,28 @@ func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
540 540
 	return detailed, nil
541 541
 }
542 542
 
543
+func parseMatchAllData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
544
+	native = nl.NativeEndian()
545
+	matchall := filter.(*MatchAll)
546
+	detailed := true
547
+	for _, datum := range data {
548
+		switch datum.Attr.Type {
549
+		case nl.TCA_MATCHALL_CLASSID:
550
+			matchall.ClassId = native.Uint32(datum.Value[0:4])
551
+		case nl.TCA_MATCHALL_ACT:
552
+			tables, err := nl.ParseRouteAttr(datum.Value)
553
+			if err != nil {
554
+				return detailed, err
555
+			}
556
+			matchall.Actions, err = parseActions(tables)
557
+			if err != nil {
558
+				return detailed, err
559
+			}
560
+		}
561
+	}
562
+	return detailed, nil
563
+}
564
+
543 565
 func AlignToAtm(size uint) uint {
544 566
 	var linksize, cells int
545 567
 	cells = int(size / nl.ATM_CELL_PAYLOAD)
... ...
@@ -562,7 +600,7 @@ func AdjustSize(sz uint, mpu uint, linklayer int) uint {
562 562
 	}
563 563
 }
564 564
 
565
-func CalcRtable(rate *nl.TcRateSpec, rtab [256]uint32, cellLog int, mtu uint32, linklayer int) int {
565
+func CalcRtable(rate *nl.TcRateSpec, rtab []uint32, cellLog int, mtu uint32, linklayer int) int {
566 566
 	bps := rate.Rate
567 567
 	mpu := rate.Mpu
568 568
 	var sz uint
569 569
new file mode 100644
... ...
@@ -0,0 +1,21 @@
0
+package netlink
1
+
2
+import (
3
+	"errors"
4
+)
5
+
6
+var (
7
+	// ErrAttrHeaderTruncated is returned when a netlink attribute's header is
8
+	// truncated.
9
+	ErrAttrHeaderTruncated = errors.New("attribute header truncated")
10
+	// ErrAttrBodyTruncated is returned when a netlink attribute's body is
11
+	// truncated.
12
+	ErrAttrBodyTruncated = errors.New("attribute body truncated")
13
+)
14
+
15
+type Fou struct {
16
+	Family    int
17
+	Port      int
18
+	Protocol  int
19
+	EncapType int
20
+}
0 21
new file mode 100644
... ...
@@ -0,0 +1,215 @@
0
+// +build linux
1
+
2
+package netlink
3
+
4
+import (
5
+	"encoding/binary"
6
+	"errors"
7
+
8
+	"github.com/vishvananda/netlink/nl"
9
+	"golang.org/x/sys/unix"
10
+)
11
+
12
+const (
13
+	FOU_GENL_NAME = "fou"
14
+)
15
+
16
+const (
17
+	FOU_CMD_UNSPEC uint8 = iota
18
+	FOU_CMD_ADD
19
+	FOU_CMD_DEL
20
+	FOU_CMD_GET
21
+	FOU_CMD_MAX = FOU_CMD_GET
22
+)
23
+
24
+const (
25
+	FOU_ATTR_UNSPEC = iota
26
+	FOU_ATTR_PORT
27
+	FOU_ATTR_AF
28
+	FOU_ATTR_IPPROTO
29
+	FOU_ATTR_TYPE
30
+	FOU_ATTR_REMCSUM_NOPARTIAL
31
+	FOU_ATTR_MAX = FOU_ATTR_REMCSUM_NOPARTIAL
32
+)
33
+
34
+const (
35
+	FOU_ENCAP_UNSPEC = iota
36
+	FOU_ENCAP_DIRECT
37
+	FOU_ENCAP_GUE
38
+	FOU_ENCAP_MAX = FOU_ENCAP_GUE
39
+)
40
+
41
+var fouFamilyId int
42
+
43
+func FouFamilyId() (int, error) {
44
+	if fouFamilyId != 0 {
45
+		return fouFamilyId, nil
46
+	}
47
+
48
+	fam, err := GenlFamilyGet(FOU_GENL_NAME)
49
+	if err != nil {
50
+		return -1, err
51
+	}
52
+
53
+	fouFamilyId = int(fam.ID)
54
+	return fouFamilyId, nil
55
+}
56
+
57
+func FouAdd(f Fou) error {
58
+	return pkgHandle.FouAdd(f)
59
+}
60
+
61
+func (h *Handle) FouAdd(f Fou) error {
62
+	fam_id, err := FouFamilyId()
63
+	if err != nil {
64
+		return err
65
+	}
66
+
67
+	// setting ip protocol conflicts with encapsulation type GUE
68
+	if f.EncapType == FOU_ENCAP_GUE && f.Protocol != 0 {
69
+		return errors.New("GUE encapsulation doesn't specify an IP protocol")
70
+	}
71
+
72
+	req := h.newNetlinkRequest(fam_id, unix.NLM_F_ACK)
73
+
74
+	// int to byte for port
75
+	bp := make([]byte, 2)
76
+	binary.BigEndian.PutUint16(bp[0:2], uint16(f.Port))
77
+
78
+	attrs := []*nl.RtAttr{
79
+		nl.NewRtAttr(FOU_ATTR_PORT, bp),
80
+		nl.NewRtAttr(FOU_ATTR_TYPE, []byte{uint8(f.EncapType)}),
81
+		nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(f.Family)}),
82
+		nl.NewRtAttr(FOU_ATTR_IPPROTO, []byte{uint8(f.Protocol)}),
83
+	}
84
+	raw := []byte{FOU_CMD_ADD, 1, 0, 0}
85
+	for _, a := range attrs {
86
+		raw = append(raw, a.Serialize()...)
87
+	}
88
+
89
+	req.AddRawData(raw)
90
+
91
+	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
92
+	if err != nil {
93
+		return err
94
+	}
95
+
96
+	return nil
97
+}
98
+
99
+func FouDel(f Fou) error {
100
+	return pkgHandle.FouDel(f)
101
+}
102
+
103
+func (h *Handle) FouDel(f Fou) error {
104
+	fam_id, err := FouFamilyId()
105
+	if err != nil {
106
+		return err
107
+	}
108
+
109
+	req := h.newNetlinkRequest(fam_id, unix.NLM_F_ACK)
110
+
111
+	// int to byte for port
112
+	bp := make([]byte, 2)
113
+	binary.BigEndian.PutUint16(bp[0:2], uint16(f.Port))
114
+
115
+	attrs := []*nl.RtAttr{
116
+		nl.NewRtAttr(FOU_ATTR_PORT, bp),
117
+		nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(f.Family)}),
118
+	}
119
+	raw := []byte{FOU_CMD_DEL, 1, 0, 0}
120
+	for _, a := range attrs {
121
+		raw = append(raw, a.Serialize()...)
122
+	}
123
+
124
+	req.AddRawData(raw)
125
+
126
+	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
127
+	if err != nil {
128
+		return err
129
+	}
130
+
131
+	return nil
132
+}
133
+
134
+func FouList(fam int) ([]Fou, error) {
135
+	return pkgHandle.FouList(fam)
136
+}
137
+
138
+func (h *Handle) FouList(fam int) ([]Fou, error) {
139
+	fam_id, err := FouFamilyId()
140
+	if err != nil {
141
+		return nil, err
142
+	}
143
+
144
+	req := h.newNetlinkRequest(fam_id, unix.NLM_F_DUMP)
145
+
146
+	attrs := []*nl.RtAttr{
147
+		nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(fam)}),
148
+	}
149
+	raw := []byte{FOU_CMD_GET, 1, 0, 0}
150
+	for _, a := range attrs {
151
+		raw = append(raw, a.Serialize()...)
152
+	}
153
+
154
+	req.AddRawData(raw)
155
+
156
+	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
157
+	if err != nil {
158
+		return nil, err
159
+	}
160
+
161
+	fous := make([]Fou, 0, len(msgs))
162
+	for _, m := range msgs {
163
+		f, err := deserializeFouMsg(m)
164
+		if err != nil {
165
+			return fous, err
166
+		}
167
+
168
+		fous = append(fous, f)
169
+	}
170
+
171
+	return fous, nil
172
+}
173
+
174
+func deserializeFouMsg(msg []byte) (Fou, error) {
175
+	// we'll skip to byte 4 to first attribute
176
+	msg = msg[3:]
177
+	var shift int
178
+	fou := Fou{}
179
+
180
+	for {
181
+		// attribute header is at least 16 bits
182
+		if len(msg) < 4 {
183
+			return fou, ErrAttrHeaderTruncated
184
+		}
185
+
186
+		lgt := int(binary.BigEndian.Uint16(msg[0:2]))
187
+		if len(msg) < lgt+4 {
188
+			return fou, ErrAttrBodyTruncated
189
+		}
190
+		attr := binary.BigEndian.Uint16(msg[2:4])
191
+
192
+		shift = lgt + 3
193
+		switch attr {
194
+		case FOU_ATTR_AF:
195
+			fou.Family = int(msg[5])
196
+		case FOU_ATTR_PORT:
197
+			fou.Port = int(binary.BigEndian.Uint16(msg[5:7]))
198
+			// port is 2 bytes
199
+			shift = lgt + 2
200
+		case FOU_ATTR_IPPROTO:
201
+			fou.Protocol = int(msg[5])
202
+		case FOU_ATTR_TYPE:
203
+			fou.EncapType = int(msg[5])
204
+		}
205
+
206
+		msg = msg[shift:]
207
+
208
+		if len(msg) < 4 {
209
+			break
210
+		}
211
+	}
212
+
213
+	return fou, nil
214
+}
0 215
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+// +build !linux
1
+
2
+package netlink
3
+
4
+func FouAdd(f Fou) error {
5
+	return ErrNotImplemented
6
+}
7
+
8
+func FouDel(f Fou) error {
9
+	return ErrNotImplemented
10
+}
11
+
12
+func FouList(fam int) ([]Fou, error) {
13
+	return nil, ErrNotImplemented
14
+}
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"syscall"
6 6
 
7 7
 	"github.com/vishvananda/netlink/nl"
8
+	"golang.org/x/sys/unix"
8 9
 )
9 10
 
10 11
 type GenlOp struct {
... ...
@@ -130,9 +131,9 @@ func (h *Handle) GenlFamilyList() ([]*GenlFamily, error) {
130 130
 		Command: nl.GENL_CTRL_CMD_GETFAMILY,
131 131
 		Version: nl.GENL_CTRL_VERSION,
132 132
 	}
133
-	req := h.newNetlinkRequest(nl.GENL_ID_CTRL, syscall.NLM_F_DUMP)
133
+	req := h.newNetlinkRequest(nl.GENL_ID_CTRL, unix.NLM_F_DUMP)
134 134
 	req.AddData(msg)
135
-	msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
135
+	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
136 136
 	if err != nil {
137 137
 		return nil, err
138 138
 	}
... ...
@@ -151,7 +152,7 @@ func (h *Handle) GenlFamilyGet(name string) (*GenlFamily, error) {
151 151
 	req := h.newNetlinkRequest(nl.GENL_ID_CTRL, 0)
152 152
 	req.AddData(msg)
153 153
 	req.AddData(nl.NewRtAttr(nl.GENL_CTRL_ATTR_FAMILY_NAME, nl.ZeroTerminated(name)))
154
-	msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
154
+	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
155 155
 	if err != nil {
156 156
 		return nil, err
157 157
 	}
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"syscall"
8 8
 
9 9
 	"github.com/vishvananda/netlink/nl"
10
+	"golang.org/x/sys/unix"
10 11
 )
11 12
 
12 13
 type PDP struct {
... ...
@@ -82,9 +83,9 @@ func (h *Handle) GTPPDPList() ([]*PDP, error) {
82 82
 		Command: nl.GENL_GTP_CMD_GETPDP,
83 83
 		Version: nl.GENL_GTP_VERSION,
84 84
 	}
85
-	req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_DUMP)
85
+	req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_DUMP)
86 86
 	req.AddData(msg)
87
-	msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
87
+	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
88 88
 	if err != nil {
89 89
 		return nil, err
90 90
 	}
... ...
@@ -96,7 +97,7 @@ func GTPPDPList() ([]*PDP, error) {
96 96
 }
97 97
 
98 98
 func gtpPDPGet(req *nl.NetlinkRequest) (*PDP, error) {
99
-	msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
99
+	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
100 100
 	if err != nil {
101 101
 		return nil, err
102 102
 	}
... ...
@@ -182,7 +183,7 @@ func (h *Handle) GTPPDPAdd(link Link, pdp *PDP) error {
182 182
 		Command: nl.GENL_GTP_CMD_NEWPDP,
183 183
 		Version: nl.GENL_GTP_VERSION,
184 184
 	}
185
-	req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
185
+	req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_EXCL|unix.NLM_F_ACK)
186 186
 	req.AddData(msg)
187 187
 	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version)))
188 188
 	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
... ...
@@ -199,7 +200,7 @@ func (h *Handle) GTPPDPAdd(link Link, pdp *PDP) error {
199 199
 	default:
200 200
 		return fmt.Errorf("unsupported GTP version: %d", pdp.Version)
201 201
 	}
202
-	_, err = req.Execute(syscall.NETLINK_GENERIC, 0)
202
+	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
203 203
 	return err
204 204
 }
205 205
 
... ...
@@ -216,7 +217,7 @@ func (h *Handle) GTPPDPDel(link Link, pdp *PDP) error {
216 216
 		Command: nl.GENL_GTP_CMD_DELPDP,
217 217
 		Version: nl.GENL_GTP_VERSION,
218 218
 	}
219
-	req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
219
+	req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_EXCL|unix.NLM_F_ACK)
220 220
 	req.AddData(msg)
221 221
 	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version)))
222 222
 	req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
... ...
@@ -229,7 +230,7 @@ func (h *Handle) GTPPDPDel(link Link, pdp *PDP) error {
229 229
 	default:
230 230
 		return fmt.Errorf("unsupported GTP version: %d", pdp.Version)
231 231
 	}
232
-	_, err = req.Execute(syscall.NETLINK_GENERIC, 0)
232
+	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
233 233
 	return err
234 234
 }
235 235
 
... ...
@@ -2,11 +2,11 @@ package netlink
2 2
 
3 3
 import (
4 4
 	"fmt"
5
-	"syscall"
6 5
 	"time"
7 6
 
8 7
 	"github.com/vishvananda/netlink/nl"
9 8
 	"github.com/vishvananda/netns"
9
+	"golang.org/x/sys/unix"
10 10
 )
11 11
 
12 12
 // Empty handle used by the netlink package methods
... ...
@@ -43,7 +43,7 @@ func (h *Handle) SetSocketTimeout(to time.Duration) error {
43 43
 	if to < time.Microsecond {
44 44
 		return fmt.Errorf("invalid timeout, minimul value is %s", time.Microsecond)
45 45
 	}
46
-	tv := syscall.NsecToTimeval(to.Nanoseconds())
46
+	tv := unix.NsecToTimeval(to.Nanoseconds())
47 47
 	for _, sh := range h.sockets {
48 48
 		if err := sh.Socket.SetSendTimeout(&tv); err != nil {
49 49
 			return err
... ...
@@ -59,13 +59,13 @@ func (h *Handle) SetSocketTimeout(to time.Duration) error {
59 59
 // socket in the netlink handle. The maximum value is capped by
60 60
 // /proc/sys/net/core/rmem_max.
61 61
 func (h *Handle) SetSocketReceiveBufferSize(size int, force bool) error {
62
-	opt := syscall.SO_RCVBUF
62
+	opt := unix.SO_RCVBUF
63 63
 	if force {
64
-		opt = syscall.SO_RCVBUFFORCE
64
+		opt = unix.SO_RCVBUFFORCE
65 65
 	}
66 66
 	for _, sh := range h.sockets {
67 67
 		fd := sh.Socket.GetFd()
68
-		err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, opt, size)
68
+		err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, opt, size)
69 69
 		if err != nil {
70 70
 			return err
71 71
 		}
... ...
@@ -81,7 +81,7 @@ func (h *Handle) GetSocketReceiveBufferSize() ([]int, error) {
81 81
 	i := 0
82 82
 	for _, sh := range h.sockets {
83 83
 		fd := sh.Socket.GetFd()
84
-		size, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF)
84
+		size, err := unix.GetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_RCVBUF)
85 85
 		if err != nil {
86 86
 			return nil, err
87 87
 		}
... ...
@@ -134,10 +134,10 @@ func (h *Handle) newNetlinkRequest(proto, flags int) *nl.NetlinkRequest {
134 134
 		return nl.NewNetlinkRequest(proto, flags)
135 135
 	}
136 136
 	return &nl.NetlinkRequest{
137
-		NlMsghdr: syscall.NlMsghdr{
138
-			Len:   uint32(syscall.SizeofNlMsghdr),
137
+		NlMsghdr: unix.NlMsghdr{
138
+			Len:   uint32(unix.SizeofNlMsghdr),
139 139
 			Type:  uint16(proto),
140
-			Flags: syscall.NLM_F_REQUEST | uint16(flags),
140
+			Flags: unix.NLM_F_REQUEST | uint16(flags),
141 141
 		},
142 142
 		Sockets: h.sockets,
143 143
 	}
... ...
@@ -220,3 +220,39 @@ func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
220 220
 func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
221 221
 	return nil, ErrNotImplemented
222 222
 }
223
+
224
+func (h *Handle) RouteAdd(route *Route) error {
225
+	return ErrNotImplemented
226
+}
227
+
228
+func (h *Handle) RouteDel(route *Route) error {
229
+	return ErrNotImplemented
230
+}
231
+
232
+func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
233
+	return nil, ErrNotImplemented
234
+}
235
+
236
+func (h *Handle) RouteList(link Link, family int) ([]Route, error) {
237
+	return nil, ErrNotImplemented
238
+}
239
+
240
+func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
241
+	return nil, ErrNotImplemented
242
+}
243
+
244
+func (h *Handle) RouteReplace(route *Route) error {
245
+	return ErrNotImplemented
246
+}
247
+
248
+func (h *Handle) RuleAdd(rule *Rule) error {
249
+	return ErrNotImplemented
250
+}
251
+
252
+func (h *Handle) RuleDel(rule *Rule) error {
253
+	return ErrNotImplemented
254
+}
255
+
256
+func (h *Handle) RuleList(family int) ([]Rule, error) {
257
+	return nil, ErrNotImplemented
258
+}
223 259
new file mode 100644
... ...
@@ -0,0 +1,98 @@
0
+package netlink
1
+
2
+import (
3
+	"syscall"
4
+	"unsafe"
5
+
6
+	"golang.org/x/sys/unix"
7
+)
8
+
9
+// ioctl for statistics.
10
+const (
11
+	// ETHTOOL_GSSET_INFO gets string set info
12
+	ETHTOOL_GSSET_INFO = 0x00000037
13
+	// SIOCETHTOOL is Ethtool interface
14
+	SIOCETHTOOL = 0x8946
15
+	// ETHTOOL_GSTRINGS gets specified string set
16
+	ETHTOOL_GSTRINGS = 0x0000001b
17
+	// ETHTOOL_GSTATS gets NIC-specific statistics
18
+	ETHTOOL_GSTATS = 0x0000001d
19
+)
20
+
21
+// string set id.
22
+const (
23
+	// ETH_SS_TEST is self-test result names, for use with %ETHTOOL_TEST
24
+	ETH_SS_TEST = iota
25
+	// ETH_SS_STATS statistic names, for use with %ETHTOOL_GSTATS
26
+	ETH_SS_STATS
27
+	// ETH_SS_PRIV_FLAGS are driver private flag names
28
+	ETH_SS_PRIV_FLAGS
29
+	// _ETH_SS_NTUPLE_FILTERS is deprecated
30
+	_ETH_SS_NTUPLE_FILTERS
31
+	// ETH_SS_FEATURES are device feature names
32
+	ETH_SS_FEATURES
33
+	// ETH_SS_RSS_HASH_FUNCS is RSS hush function names
34
+	ETH_SS_RSS_HASH_FUNCS
35
+)
36
+
37
+// IfreqSlave is a struct for ioctl bond manipulation syscalls.
38
+// It is used to assign slave to bond interface with Name.
39
+type IfreqSlave struct {
40
+	Name  [unix.IFNAMSIZ]byte
41
+	Slave [unix.IFNAMSIZ]byte
42
+}
43
+
44
+// Ifreq is a struct for ioctl ethernet manipulation syscalls.
45
+type Ifreq struct {
46
+	Name [unix.IFNAMSIZ]byte
47
+	Data uintptr
48
+}
49
+
50
+// ethtoolSset is a string set information
51
+type ethtoolSset struct {
52
+	cmd      uint32
53
+	reserved uint32
54
+	mask     uint64
55
+	data     [1]uint32
56
+}
57
+
58
+// ethtoolGstrings is string set for data tagging
59
+type ethtoolGstrings struct {
60
+	cmd       uint32
61
+	stringSet uint32
62
+	length    uint32
63
+	data      [32]byte
64
+}
65
+
66
+type ethtoolStats struct {
67
+	cmd    uint32
68
+	nStats uint32
69
+	data   [1]uint64
70
+}
71
+
72
+// newIocltSlaveReq returns filled IfreqSlave with proper interface names
73
+// It is used by ioctl to assign slave to bond master
74
+func newIocltSlaveReq(slave, master string) *IfreqSlave {
75
+	ifreq := &IfreqSlave{}
76
+	copy(ifreq.Name[:unix.IFNAMSIZ-1], master)
77
+	copy(ifreq.Slave[:unix.IFNAMSIZ-1], slave)
78
+	return ifreq
79
+}
80
+
81
+// newIocltStringSetReq creates request to get interface string set
82
+func newIocltStringSetReq(linkName string) (*Ifreq, *ethtoolSset) {
83
+	e := &ethtoolSset{
84
+		cmd:  ETHTOOL_GSSET_INFO,
85
+		mask: 1 << ETH_SS_STATS,
86
+	}
87
+
88
+	ifreq := &Ifreq{Data: uintptr(unsafe.Pointer(e))}
89
+	copy(ifreq.Name[:unix.IFNAMSIZ-1], linkName)
90
+	return ifreq, e
91
+}
92
+
93
+// getSocketUDP returns file descriptor to new UDP socket
94
+// It is used for communication with ioctl interface.
95
+func getSocketUDP() (int, error) {
96
+	return syscall.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
97
+}
... ...
@@ -3,6 +3,7 @@ package netlink
3 3
 import (
4 4
 	"fmt"
5 5
 	"net"
6
+	"os"
6 7
 )
7 8
 
8 9
 // Link represents a link device from netlink. Shared link attributes
... ...
@@ -38,6 +39,8 @@ type LinkAttrs struct {
38 38
 	Protinfo     *Protinfo
39 39
 	OperState    LinkOperState
40 40
 	NetNsID      int
41
+	NumTxQueues  int
42
+	NumRxQueues  int
41 43
 }
42 44
 
43 45
 // LinkOperState represents the values of the IFLA_OPERSTATE link
... ...
@@ -259,6 +262,9 @@ const (
259 259
 type Macvlan struct {
260 260
 	LinkAttrs
261 261
 	Mode MacvlanMode
262
+
263
+	// MACAddrs is only populated for Macvlan SOURCE links
264
+	MACAddrs []net.HardwareAddr
262 265
 }
263 266
 
264 267
 func (macvlan *Macvlan) Attrs() *LinkAttrs {
... ...
@@ -284,8 +290,10 @@ type TuntapFlag uint16
284 284
 // Tuntap links created via /dev/tun/tap, but can be destroyed via netlink
285 285
 type Tuntap struct {
286 286
 	LinkAttrs
287
-	Mode  TuntapMode
288
-	Flags TuntapFlag
287
+	Mode   TuntapMode
288
+	Flags  TuntapFlag
289
+	Queues int
290
+	Fds    []*os.File
289 291
 }
290 292
 
291 293
 func (tuntap *Tuntap) Attrs() *LinkAttrs {
... ...
@@ -327,26 +335,28 @@ func (generic *GenericLink) Type() string {
327 327
 
328 328
 type Vxlan struct {
329 329
 	LinkAttrs
330
-	VxlanId      int
331
-	VtepDevIndex int
332
-	SrcAddr      net.IP
333
-	Group        net.IP
334
-	TTL          int
335
-	TOS          int
336
-	Learning     bool
337
-	Proxy        bool
338
-	RSC          bool
339
-	L2miss       bool
340
-	L3miss       bool
341
-	UDPCSum      bool
342
-	NoAge        bool
343
-	GBP          bool
344
-	FlowBased    bool
345
-	Age          int
346
-	Limit        int
347
-	Port         int
348
-	PortLow      int
349
-	PortHigh     int
330
+	VxlanId        int
331
+	VtepDevIndex   int
332
+	SrcAddr        net.IP
333
+	Group          net.IP
334
+	TTL            int
335
+	TOS            int
336
+	Learning       bool
337
+	Proxy          bool
338
+	RSC            bool
339
+	L2miss         bool
340
+	L3miss         bool
341
+	UDPCSum        bool
342
+	UDP6ZeroCSumTx bool
343
+	UDP6ZeroCSumRx bool
344
+	NoAge          bool
345
+	GBP            bool
346
+	FlowBased      bool
347
+	Age            int
348
+	Limit          int
349
+	Port           int
350
+	PortLow        int
351
+	PortHigh       int
350 352
 }
351 353
 
352 354
 func (vxlan *Vxlan) Attrs() *LinkAttrs {
... ...
@@ -695,17 +705,25 @@ func (gretap *Gretap) Attrs() *LinkAttrs {
695 695
 }
696 696
 
697 697
 func (gretap *Gretap) Type() string {
698
+	if gretap.Local.To4() == nil {
699
+		return "ip6gretap"
700
+	}
698 701
 	return "gretap"
699 702
 }
700 703
 
701 704
 type Iptun struct {
702 705
 	LinkAttrs
703
-	Ttl      uint8
704
-	Tos      uint8
705
-	PMtuDisc uint8
706
-	Link     uint32
707
-	Local    net.IP
708
-	Remote   net.IP
706
+	Ttl        uint8
707
+	Tos        uint8
708
+	PMtuDisc   uint8
709
+	Link       uint32
710
+	Local      net.IP
711
+	Remote     net.IP
712
+	EncapSport uint16
713
+	EncapDport uint16
714
+	EncapType  uint16
715
+	EncapFlags uint16
716
+	FlowBased  bool
709 717
 }
710 718
 
711 719
 func (iptun *Iptun) Attrs() *LinkAttrs {
... ...
@@ -716,6 +734,28 @@ func (iptun *Iptun) Type() string {
716 716
 	return "ipip"
717 717
 }
718 718
 
719
+type Sittun struct {
720
+	LinkAttrs
721
+	Link       uint32
722
+	Local      net.IP
723
+	Remote     net.IP
724
+	Ttl        uint8
725
+	Tos        uint8
726
+	PMtuDisc   uint8
727
+	EncapType  uint16
728
+	EncapFlags uint16
729
+	EncapSport uint16
730
+	EncapDport uint16
731
+}
732
+
733
+func (sittun *Sittun) Attrs() *LinkAttrs {
734
+	return &sittun.LinkAttrs
735
+}
736
+
737
+func (sittun *Sittun) Type() string {
738
+	return "sit"
739
+}
740
+
719 741
 type Vti struct {
720 742
 	LinkAttrs
721 743
 	IKey   uint32
... ...
@@ -735,16 +775,20 @@ func (iptun *Vti) Type() string {
735 735
 
736 736
 type Gretun struct {
737 737
 	LinkAttrs
738
-	Link     uint32
739
-	IFlags   uint16
740
-	OFlags   uint16
741
-	IKey     uint32
742
-	OKey     uint32
743
-	Local    net.IP
744
-	Remote   net.IP
745
-	Ttl      uint8
746
-	Tos      uint8
747
-	PMtuDisc uint8
738
+	Link       uint32
739
+	IFlags     uint16
740
+	OFlags     uint16
741
+	IKey       uint32
742
+	OKey       uint32
743
+	Local      net.IP
744
+	Remote     net.IP
745
+	Ttl        uint8
746
+	Tos        uint8
747
+	PMtuDisc   uint8
748
+	EncapType  uint16
749
+	EncapFlags uint16
750
+	EncapSport uint16
751
+	EncapDport uint16
748 752
 }
749 753
 
750 754
 func (gretun *Gretun) Attrs() *LinkAttrs {
... ...
@@ -752,6 +796,9 @@ func (gretun *Gretun) Attrs() *LinkAttrs {
752 752
 }
753 753
 
754 754
 func (gretun *Gretun) Type() string {
755
+	if gretun.Local.To4() == nil {
756
+		return "ip6gre"
757
+	}
755 758
 	return "gre"
756 759
 }
757 760
 
... ...
@@ -11,22 +11,24 @@ import (
11 11
 
12 12
 	"github.com/vishvananda/netlink/nl"
13 13
 	"github.com/vishvananda/netns"
14
+	"golang.org/x/sys/unix"
14 15
 )
15 16
 
16 17
 const (
17 18
 	SizeofLinkStats32 = 0x5c
18 19
 	SizeofLinkStats64 = 0xd8
19
-	IFLA_STATS64      = 0x17 // syscall pkg does not contain this one
20 20
 )
21 21
 
22 22
 const (
23
-	TUNTAP_MODE_TUN  TuntapMode = syscall.IFF_TUN
24
-	TUNTAP_MODE_TAP  TuntapMode = syscall.IFF_TAP
25
-	TUNTAP_DEFAULTS  TuntapFlag = syscall.IFF_TUN_EXCL | syscall.IFF_ONE_QUEUE
26
-	TUNTAP_VNET_HDR  TuntapFlag = syscall.IFF_VNET_HDR
27
-	TUNTAP_TUN_EXCL  TuntapFlag = syscall.IFF_TUN_EXCL
28
-	TUNTAP_NO_PI     TuntapFlag = syscall.IFF_NO_PI
29
-	TUNTAP_ONE_QUEUE TuntapFlag = syscall.IFF_ONE_QUEUE
23
+	TUNTAP_MODE_TUN             TuntapMode = unix.IFF_TUN
24
+	TUNTAP_MODE_TAP             TuntapMode = unix.IFF_TAP
25
+	TUNTAP_DEFAULTS             TuntapFlag = unix.IFF_TUN_EXCL | unix.IFF_ONE_QUEUE
26
+	TUNTAP_VNET_HDR             TuntapFlag = unix.IFF_VNET_HDR
27
+	TUNTAP_TUN_EXCL             TuntapFlag = unix.IFF_TUN_EXCL
28
+	TUNTAP_NO_PI                TuntapFlag = unix.IFF_NO_PI
29
+	TUNTAP_ONE_QUEUE            TuntapFlag = unix.IFF_ONE_QUEUE
30
+	TUNTAP_MULTI_QUEUE          TuntapFlag = unix.IFF_MULTI_QUEUE
31
+	TUNTAP_MULTI_QUEUE_DEFAULTS TuntapFlag = TUNTAP_MULTI_QUEUE | TUNTAP_NO_PI
30 32
 )
31 33
 
32 34
 var lookupByDump = false
... ...
@@ -61,15 +63,15 @@ func (h *Handle) ensureIndex(link *LinkAttrs) {
61 61
 func (h *Handle) LinkSetARPOff(link Link) error {
62 62
 	base := link.Attrs()
63 63
 	h.ensureIndex(base)
64
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
64
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
65 65
 
66
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
67
-	msg.Change |= syscall.IFF_NOARP
68
-	msg.Flags |= syscall.IFF_NOARP
66
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
67
+	msg.Change |= unix.IFF_NOARP
68
+	msg.Flags |= unix.IFF_NOARP
69 69
 	msg.Index = int32(base.Index)
70 70
 	req.AddData(msg)
71 71
 
72
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
72
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
73 73
 	return err
74 74
 }
75 75
 
... ...
@@ -80,15 +82,15 @@ func LinkSetARPOff(link Link) error {
80 80
 func (h *Handle) LinkSetARPOn(link Link) error {
81 81
 	base := link.Attrs()
82 82
 	h.ensureIndex(base)
83
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
83
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
84 84
 
85
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
86
-	msg.Change |= syscall.IFF_NOARP
87
-	msg.Flags &= ^uint32(syscall.IFF_NOARP)
85
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
86
+	msg.Change |= unix.IFF_NOARP
87
+	msg.Flags &= ^uint32(unix.IFF_NOARP)
88 88
 	msg.Index = int32(base.Index)
89 89
 	req.AddData(msg)
90 90
 
91
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
91
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
92 92
 	return err
93 93
 }
94 94
 
... ...
@@ -99,15 +101,84 @@ func LinkSetARPOn(link Link) error {
99 99
 func (h *Handle) SetPromiscOn(link Link) error {
100 100
 	base := link.Attrs()
101 101
 	h.ensureIndex(base)
102
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
102
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
103 103
 
104
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
105
-	msg.Change = syscall.IFF_PROMISC
106
-	msg.Flags = syscall.IFF_PROMISC
104
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
105
+	msg.Change = unix.IFF_PROMISC
106
+	msg.Flags = unix.IFF_PROMISC
107 107
 	msg.Index = int32(base.Index)
108 108
 	req.AddData(msg)
109 109
 
110
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
110
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
111
+	return err
112
+}
113
+
114
+func MacvlanMACAddrAdd(link Link, addr net.HardwareAddr) error {
115
+	return pkgHandle.MacvlanMACAddrAdd(link, addr)
116
+}
117
+
118
+func (h *Handle) MacvlanMACAddrAdd(link Link, addr net.HardwareAddr) error {
119
+	return h.macvlanMACAddrChange(link, []net.HardwareAddr{addr}, nl.MACVLAN_MACADDR_ADD)
120
+}
121
+
122
+func MacvlanMACAddrDel(link Link, addr net.HardwareAddr) error {
123
+	return pkgHandle.MacvlanMACAddrDel(link, addr)
124
+}
125
+
126
+func (h *Handle) MacvlanMACAddrDel(link Link, addr net.HardwareAddr) error {
127
+	return h.macvlanMACAddrChange(link, []net.HardwareAddr{addr}, nl.MACVLAN_MACADDR_DEL)
128
+}
129
+
130
+func MacvlanMACAddrFlush(link Link) error {
131
+	return pkgHandle.MacvlanMACAddrFlush(link)
132
+}
133
+
134
+func (h *Handle) MacvlanMACAddrFlush(link Link) error {
135
+	return h.macvlanMACAddrChange(link, nil, nl.MACVLAN_MACADDR_FLUSH)
136
+}
137
+
138
+func MacvlanMACAddrSet(link Link, addrs []net.HardwareAddr) error {
139
+	return pkgHandle.MacvlanMACAddrSet(link, addrs)
140
+}
141
+
142
+func (h *Handle) MacvlanMACAddrSet(link Link, addrs []net.HardwareAddr) error {
143
+	return h.macvlanMACAddrChange(link, addrs, nl.MACVLAN_MACADDR_SET)
144
+}
145
+
146
+func (h *Handle) macvlanMACAddrChange(link Link, addrs []net.HardwareAddr, mode uint32) error {
147
+	base := link.Attrs()
148
+	h.ensureIndex(base)
149
+	req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
150
+
151
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
152
+	msg.Index = int32(base.Index)
153
+	req.AddData(msg)
154
+
155
+	linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil)
156
+	nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
157
+	inner := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
158
+
159
+	// IFLA_MACVLAN_MACADDR_MODE = mode
160
+	b := make([]byte, 4)
161
+	native.PutUint32(b, mode)
162
+	nl.NewRtAttrChild(inner, nl.IFLA_MACVLAN_MACADDR_MODE, b)
163
+
164
+	// populate message with MAC addrs, if necessary
165
+	switch mode {
166
+	case nl.MACVLAN_MACADDR_ADD, nl.MACVLAN_MACADDR_DEL:
167
+		if len(addrs) == 1 {
168
+			nl.NewRtAttrChild(inner, nl.IFLA_MACVLAN_MACADDR, []byte(addrs[0]))
169
+		}
170
+	case nl.MACVLAN_MACADDR_SET:
171
+		mad := nl.NewRtAttrChild(inner, nl.IFLA_MACVLAN_MACADDR_DATA, nil)
172
+		for _, addr := range addrs {
173
+			nl.NewRtAttrChild(mad, nl.IFLA_MACVLAN_MACADDR, []byte(addr))
174
+		}
175
+	}
176
+
177
+	req.AddData(linkInfo)
178
+
179
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
111 180
 	return err
112 181
 }
113 182
 
... ...
@@ -118,7 +189,7 @@ func BridgeSetMcastSnoop(link Link, on bool) error {
118 118
 func (h *Handle) BridgeSetMcastSnoop(link Link, on bool) error {
119 119
 	bridge := link.(*Bridge)
120 120
 	bridge.MulticastSnooping = &on
121
-	return h.linkModify(bridge, syscall.NLM_F_ACK)
121
+	return h.linkModify(bridge, unix.NLM_F_ACK)
122 122
 }
123 123
 
124 124
 func SetPromiscOn(link Link) error {
... ...
@@ -128,15 +199,15 @@ func SetPromiscOn(link Link) error {
128 128
 func (h *Handle) SetPromiscOff(link Link) error {
129 129
 	base := link.Attrs()
130 130
 	h.ensureIndex(base)
131
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
131
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
132 132
 
133
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
134
-	msg.Change = syscall.IFF_PROMISC
135
-	msg.Flags = 0 & ^syscall.IFF_PROMISC
133
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
134
+	msg.Change = unix.IFF_PROMISC
135
+	msg.Flags = 0 & ^unix.IFF_PROMISC
136 136
 	msg.Index = int32(base.Index)
137 137
 	req.AddData(msg)
138 138
 
139
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
139
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
140 140
 	return err
141 141
 }
142 142
 
... ...
@@ -155,15 +226,15 @@ func LinkSetUp(link Link) error {
155 155
 func (h *Handle) LinkSetUp(link Link) error {
156 156
 	base := link.Attrs()
157 157
 	h.ensureIndex(base)
158
-	req := h.newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
158
+	req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
159 159
 
160
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
161
-	msg.Change = syscall.IFF_UP
162
-	msg.Flags = syscall.IFF_UP
160
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
161
+	msg.Change = unix.IFF_UP
162
+	msg.Flags = unix.IFF_UP
163 163
 	msg.Index = int32(base.Index)
164 164
 	req.AddData(msg)
165 165
 
166
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
166
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
167 167
 	return err
168 168
 }
169 169
 
... ...
@@ -178,15 +249,15 @@ func LinkSetDown(link Link) error {
178 178
 func (h *Handle) LinkSetDown(link Link) error {
179 179
 	base := link.Attrs()
180 180
 	h.ensureIndex(base)
181
-	req := h.newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
181
+	req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
182 182
 
183
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
184
-	msg.Change = syscall.IFF_UP
185
-	msg.Flags = 0 & ^syscall.IFF_UP
183
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
184
+	msg.Change = unix.IFF_UP
185
+	msg.Flags = 0 & ^unix.IFF_UP
186 186
 	msg.Index = int32(base.Index)
187 187
 	req.AddData(msg)
188 188
 
189
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
189
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
190 190
 	return err
191 191
 }
192 192
 
... ...
@@ -201,19 +272,19 @@ func LinkSetMTU(link Link, mtu int) error {
201 201
 func (h *Handle) LinkSetMTU(link Link, mtu int) error {
202 202
 	base := link.Attrs()
203 203
 	h.ensureIndex(base)
204
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
204
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
205 205
 
206
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
206
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
207 207
 	msg.Index = int32(base.Index)
208 208
 	req.AddData(msg)
209 209
 
210 210
 	b := make([]byte, 4)
211 211
 	native.PutUint32(b, uint32(mtu))
212 212
 
213
-	data := nl.NewRtAttr(syscall.IFLA_MTU, b)
213
+	data := nl.NewRtAttr(unix.IFLA_MTU, b)
214 214
 	req.AddData(data)
215 215
 
216
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
216
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
217 217
 	return err
218 218
 }
219 219
 
... ...
@@ -228,16 +299,16 @@ func LinkSetName(link Link, name string) error {
228 228
 func (h *Handle) LinkSetName(link Link, name string) error {
229 229
 	base := link.Attrs()
230 230
 	h.ensureIndex(base)
231
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
231
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
232 232
 
233
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
233
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
234 234
 	msg.Index = int32(base.Index)
235 235
 	req.AddData(msg)
236 236
 
237
-	data := nl.NewRtAttr(syscall.IFLA_IFNAME, []byte(name))
237
+	data := nl.NewRtAttr(unix.IFLA_IFNAME, []byte(name))
238 238
 	req.AddData(data)
239 239
 
240
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
240
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
241 241
 	return err
242 242
 }
243 243
 
... ...
@@ -252,16 +323,16 @@ func LinkSetAlias(link Link, name string) error {
252 252
 func (h *Handle) LinkSetAlias(link Link, name string) error {
253 253
 	base := link.Attrs()
254 254
 	h.ensureIndex(base)
255
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
255
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
256 256
 
257
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
257
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
258 258
 	msg.Index = int32(base.Index)
259 259
 	req.AddData(msg)
260 260
 
261
-	data := nl.NewRtAttr(syscall.IFLA_IFALIAS, []byte(name))
261
+	data := nl.NewRtAttr(unix.IFLA_IFALIAS, []byte(name))
262 262
 	req.AddData(data)
263 263
 
264
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
264
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
265 265
 	return err
266 266
 }
267 267
 
... ...
@@ -276,16 +347,16 @@ func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
276 276
 func (h *Handle) LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
277 277
 	base := link.Attrs()
278 278
 	h.ensureIndex(base)
279
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
279
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
280 280
 
281
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
281
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
282 282
 	msg.Index = int32(base.Index)
283 283
 	req.AddData(msg)
284 284
 
285
-	data := nl.NewRtAttr(syscall.IFLA_ADDRESS, []byte(hwaddr))
285
+	data := nl.NewRtAttr(unix.IFLA_ADDRESS, []byte(hwaddr))
286 286
 	req.AddData(data)
287 287
 
288
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
288
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
289 289
 	return err
290 290
 }
291 291
 
... ...
@@ -300,13 +371,13 @@ func LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
300 300
 func (h *Handle) LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
301 301
 	base := link.Attrs()
302 302
 	h.ensureIndex(base)
303
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
303
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
304 304
 
305
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
305
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
306 306
 	msg.Index = int32(base.Index)
307 307
 	req.AddData(msg)
308 308
 
309
-	data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil)
309
+	data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
310 310
 	info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
311 311
 	vfmsg := nl.VfMac{
312 312
 		Vf: uint32(vf),
... ...
@@ -315,7 +386,7 @@ func (h *Handle) LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAdd
315 315
 	nl.NewRtAttrChild(info, nl.IFLA_VF_MAC, vfmsg.Serialize())
316 316
 	req.AddData(data)
317 317
 
318
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
318
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
319 319
 	return err
320 320
 }
321 321
 
... ...
@@ -330,13 +401,13 @@ func LinkSetVfVlan(link Link, vf, vlan int) error {
330 330
 func (h *Handle) LinkSetVfVlan(link Link, vf, vlan int) error {
331 331
 	base := link.Attrs()
332 332
 	h.ensureIndex(base)
333
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
333
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
334 334
 
335
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
335
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
336 336
 	msg.Index = int32(base.Index)
337 337
 	req.AddData(msg)
338 338
 
339
-	data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil)
339
+	data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
340 340
 	info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
341 341
 	vfmsg := nl.VfVlan{
342 342
 		Vf:   uint32(vf),
... ...
@@ -345,7 +416,7 @@ func (h *Handle) LinkSetVfVlan(link Link, vf, vlan int) error {
345 345
 	nl.NewRtAttrChild(info, nl.IFLA_VF_VLAN, vfmsg.Serialize())
346 346
 	req.AddData(data)
347 347
 
348
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
348
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
349 349
 	return err
350 350
 }
351 351
 
... ...
@@ -360,13 +431,13 @@ func LinkSetVfTxRate(link Link, vf, rate int) error {
360 360
 func (h *Handle) LinkSetVfTxRate(link Link, vf, rate int) error {
361 361
 	base := link.Attrs()
362 362
 	h.ensureIndex(base)
363
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
363
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
364 364
 
365
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
365
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
366 366
 	msg.Index = int32(base.Index)
367 367
 	req.AddData(msg)
368 368
 
369
-	data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil)
369
+	data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
370 370
 	info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
371 371
 	vfmsg := nl.VfTxRate{
372 372
 		Vf:   uint32(vf),
... ...
@@ -375,7 +446,7 @@ func (h *Handle) LinkSetVfTxRate(link Link, vf, rate int) error {
375 375
 	nl.NewRtAttrChild(info, nl.IFLA_VF_TX_RATE, vfmsg.Serialize())
376 376
 	req.AddData(data)
377 377
 
378
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
378
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
379 379
 	return err
380 380
 }
381 381
 
... ...
@@ -391,13 +462,13 @@ func (h *Handle) LinkSetVfSpoofchk(link Link, vf int, check bool) error {
391 391
 	var setting uint32
392 392
 	base := link.Attrs()
393 393
 	h.ensureIndex(base)
394
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
394
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
395 395
 
396
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
396
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
397 397
 	msg.Index = int32(base.Index)
398 398
 	req.AddData(msg)
399 399
 
400
-	data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil)
400
+	data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
401 401
 	info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
402 402
 	if check {
403 403
 		setting = 1
... ...
@@ -409,7 +480,7 @@ func (h *Handle) LinkSetVfSpoofchk(link Link, vf int, check bool) error {
409 409
 	nl.NewRtAttrChild(info, nl.IFLA_VF_SPOOFCHK, vfmsg.Serialize())
410 410
 	req.AddData(data)
411 411
 
412
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
412
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
413 413
 	return err
414 414
 }
415 415
 
... ...
@@ -425,13 +496,13 @@ func (h *Handle) LinkSetVfTrust(link Link, vf int, state bool) error {
425 425
 	var setting uint32
426 426
 	base := link.Attrs()
427 427
 	h.ensureIndex(base)
428
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
428
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
429 429
 
430
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
430
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
431 431
 	msg.Index = int32(base.Index)
432 432
 	req.AddData(msg)
433 433
 
434
-	data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil)
434
+	data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
435 435
 	info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
436 436
 	if state {
437 437
 		setting = 1
... ...
@@ -443,7 +514,7 @@ func (h *Handle) LinkSetVfTrust(link Link, vf int, state bool) error {
443 443
 	nl.NewRtAttrChild(info, nl.IFLA_VF_TRUST, vfmsg.Serialize())
444 444
 	req.AddData(data)
445 445
 
446
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
446
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
447 447
 	return err
448 448
 }
449 449
 
... ...
@@ -491,19 +562,19 @@ func LinkSetMasterByIndex(link Link, masterIndex int) error {
491 491
 func (h *Handle) LinkSetMasterByIndex(link Link, masterIndex int) error {
492 492
 	base := link.Attrs()
493 493
 	h.ensureIndex(base)
494
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
494
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
495 495
 
496
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
496
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
497 497
 	msg.Index = int32(base.Index)
498 498
 	req.AddData(msg)
499 499
 
500 500
 	b := make([]byte, 4)
501 501
 	native.PutUint32(b, uint32(masterIndex))
502 502
 
503
-	data := nl.NewRtAttr(syscall.IFLA_MASTER, b)
503
+	data := nl.NewRtAttr(unix.IFLA_MASTER, b)
504 504
 	req.AddData(data)
505 505
 
506
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
506
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
507 507
 	return err
508 508
 }
509 509
 
... ...
@@ -520,19 +591,19 @@ func LinkSetNsPid(link Link, nspid int) error {
520 520
 func (h *Handle) LinkSetNsPid(link Link, nspid int) error {
521 521
 	base := link.Attrs()
522 522
 	h.ensureIndex(base)
523
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
523
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
524 524
 
525
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
525
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
526 526
 	msg.Index = int32(base.Index)
527 527
 	req.AddData(msg)
528 528
 
529 529
 	b := make([]byte, 4)
530 530
 	native.PutUint32(b, uint32(nspid))
531 531
 
532
-	data := nl.NewRtAttr(syscall.IFLA_NET_NS_PID, b)
532
+	data := nl.NewRtAttr(unix.IFLA_NET_NS_PID, b)
533 533
 	req.AddData(data)
534 534
 
535
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
535
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
536 536
 	return err
537 537
 }
538 538
 
... ...
@@ -549,19 +620,19 @@ func LinkSetNsFd(link Link, fd int) error {
549 549
 func (h *Handle) LinkSetNsFd(link Link, fd int) error {
550 550
 	base := link.Attrs()
551 551
 	h.ensureIndex(base)
552
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
552
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
553 553
 
554
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
554
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
555 555
 	msg.Index = int32(base.Index)
556 556
 	req.AddData(msg)
557 557
 
558 558
 	b := make([]byte, 4)
559 559
 	native.PutUint32(b, uint32(fd))
560 560
 
561
-	data := nl.NewRtAttr(nl.IFLA_NET_NS_FD, b)
561
+	data := nl.NewRtAttr(unix.IFLA_NET_NS_FD, b)
562 562
 	req.AddData(data)
563 563
 
564
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
564
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
565 565
 	return err
566 566
 }
567 567
 
... ...
@@ -576,15 +647,15 @@ func LinkSetXdpFd(link Link, fd int) error {
576 576
 func LinkSetXdpFdWithFlags(link Link, fd, flags int) error {
577 577
 	base := link.Attrs()
578 578
 	ensureIndex(base)
579
-	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
579
+	req := nl.NewNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
580 580
 
581
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
581
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
582 582
 	msg.Index = int32(base.Index)
583 583
 	req.AddData(msg)
584 584
 
585 585
 	addXdpAttrs(&LinkXdp{Fd: fd, Flags: uint32(flags)}, req)
586 586
 
587
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
587
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
588 588
 	return err
589 589
 }
590 590
 
... ...
@@ -642,6 +713,8 @@ func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) {
642 642
 	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_RSC, boolAttr(vxlan.RSC))
643 643
 	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss))
644 644
 	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss))
645
+	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_UDP_ZERO_CSUM6_TX, boolAttr(vxlan.UDP6ZeroCSumTx))
646
+	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_UDP_ZERO_CSUM6_RX, boolAttr(vxlan.UDP6ZeroCSumRx))
645 647
 
646 648
 	if vxlan.UDPCSum {
647 649
 		nl.NewRtAttrChild(data, nl.IFLA_VXLAN_UDP_CSUM, boolAttr(vxlan.UDPCSum))
... ...
@@ -766,6 +839,12 @@ func addBondAttrs(bond *Bond, linkInfo *nl.RtAttr) {
766 766
 	}
767 767
 }
768 768
 
769
+func cleanupFds(fds []*os.File) {
770
+	for _, f := range fds {
771
+		f.Close()
772
+	}
773
+}
774
+
769 775
 // LinkAdd adds a new link device. The type and features of the device
770 776
 // are taken from the parameters in the link object.
771 777
 // Equivalent to: `ip link add $link`
... ...
@@ -777,7 +856,7 @@ func LinkAdd(link Link) error {
777 777
 // are taken fromt the parameters in the link object.
778 778
 // Equivalent to: `ip link add $link`
779 779
 func (h *Handle) LinkAdd(link Link) error {
780
-	return h.linkModify(link, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
780
+	return h.linkModify(link, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
781 781
 }
782 782
 
783 783
 func (h *Handle) linkModify(link Link, flags int) error {
... ...
@@ -791,104 +870,155 @@ func (h *Handle) linkModify(link Link, flags int) error {
791 791
 	if tuntap, ok := link.(*Tuntap); ok {
792 792
 		// TODO: support user
793 793
 		// TODO: support group
794
-		// TODO: multi_queue
795 794
 		// TODO: support non- persistent
796
-		if tuntap.Mode < syscall.IFF_TUN || tuntap.Mode > syscall.IFF_TAP {
795
+		if tuntap.Mode < unix.IFF_TUN || tuntap.Mode > unix.IFF_TAP {
797 796
 			return fmt.Errorf("Tuntap.Mode %v unknown!", tuntap.Mode)
798 797
 		}
799
-		file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
800
-		if err != nil {
801
-			return err
802
-		}
803
-		defer file.Close()
798
+
799
+		queues := tuntap.Queues
800
+
801
+		var fds []*os.File
804 802
 		var req ifReq
805
-		if tuntap.Flags == 0 {
806
-			req.Flags = uint16(TUNTAP_DEFAULTS)
803
+		copy(req.Name[:15], base.Name)
804
+
805
+		req.Flags = uint16(tuntap.Flags)
806
+
807
+		if queues == 0 { //Legacy compatibility
808
+			queues = 1
809
+			if tuntap.Flags == 0 {
810
+				req.Flags = uint16(TUNTAP_DEFAULTS)
811
+			}
807 812
 		} else {
808
-			req.Flags = uint16(tuntap.Flags)
813
+			// For best peformance set Flags to TUNTAP_MULTI_QUEUE_DEFAULTS | TUNTAP_VNET_HDR
814
+			// when a) KVM has support for this ABI and
815
+			//      b) the value of the flag is queryable using the TUNGETIFF ioctl
816
+			if tuntap.Flags == 0 {
817
+				req.Flags = uint16(TUNTAP_MULTI_QUEUE_DEFAULTS)
818
+			}
809 819
 		}
820
+
810 821
 		req.Flags |= uint16(tuntap.Mode)
811
-		copy(req.Name[:15], base.Name)
812
-		_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), uintptr(syscall.TUNSETIFF), uintptr(unsafe.Pointer(&req)))
813
-		if errno != 0 {
814
-			return fmt.Errorf("Tuntap IOCTL TUNSETIFF failed, errno %v", errno)
822
+
823
+		for i := 0; i < queues; i++ {
824
+			localReq := req
825
+			file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
826
+			if err != nil {
827
+				cleanupFds(fds)
828
+				return err
829
+			}
830
+
831
+			fds = append(fds, file)
832
+			_, _, errno := unix.Syscall(unix.SYS_IOCTL, file.Fd(), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&localReq)))
833
+			if errno != 0 {
834
+				cleanupFds(fds)
835
+				return fmt.Errorf("Tuntap IOCTL TUNSETIFF failed [%d], errno %v", i, errno)
836
+			}
815 837
 		}
816
-		_, _, errno = syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), uintptr(syscall.TUNSETPERSIST), 1)
838
+
839
+		_, _, errno := unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 1)
817 840
 		if errno != 0 {
841
+			cleanupFds(fds)
818 842
 			return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno)
819 843
 		}
844
+
820 845
 		h.ensureIndex(base)
821 846
 
822 847
 		// can't set master during create, so set it afterwards
823 848
 		if base.MasterIndex != 0 {
824 849
 			// TODO: verify MasterIndex is actually a bridge?
825
-			return h.LinkSetMasterByIndex(link, base.MasterIndex)
850
+			err := h.LinkSetMasterByIndex(link, base.MasterIndex)
851
+			if err != nil {
852
+				_, _, _ = unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 0)
853
+				cleanupFds(fds)
854
+				return err
855
+			}
856
+		}
857
+
858
+		if tuntap.Queues == 0 {
859
+			cleanupFds(fds)
860
+		} else {
861
+			tuntap.Fds = fds
826 862
 		}
863
+
827 864
 		return nil
828 865
 	}
829 866
 
830
-	req := h.newNetlinkRequest(syscall.RTM_NEWLINK, flags)
867
+	req := h.newNetlinkRequest(unix.RTM_NEWLINK, flags)
831 868
 
832
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
869
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
833 870
 	// TODO: make it shorter
834 871
 	if base.Flags&net.FlagUp != 0 {
835
-		msg.Change = syscall.IFF_UP
836
-		msg.Flags = syscall.IFF_UP
872
+		msg.Change = unix.IFF_UP
873
+		msg.Flags = unix.IFF_UP
837 874
 	}
838 875
 	if base.Flags&net.FlagBroadcast != 0 {
839
-		msg.Change |= syscall.IFF_BROADCAST
840
-		msg.Flags |= syscall.IFF_BROADCAST
876
+		msg.Change |= unix.IFF_BROADCAST
877
+		msg.Flags |= unix.IFF_BROADCAST
841 878
 	}
842 879
 	if base.Flags&net.FlagLoopback != 0 {
843
-		msg.Change |= syscall.IFF_LOOPBACK
844
-		msg.Flags |= syscall.IFF_LOOPBACK
880
+		msg.Change |= unix.IFF_LOOPBACK
881
+		msg.Flags |= unix.IFF_LOOPBACK
845 882
 	}
846 883
 	if base.Flags&net.FlagPointToPoint != 0 {
847
-		msg.Change |= syscall.IFF_POINTOPOINT
848
-		msg.Flags |= syscall.IFF_POINTOPOINT
884
+		msg.Change |= unix.IFF_POINTOPOINT
885
+		msg.Flags |= unix.IFF_POINTOPOINT
849 886
 	}
850 887
 	if base.Flags&net.FlagMulticast != 0 {
851
-		msg.Change |= syscall.IFF_MULTICAST
852
-		msg.Flags |= syscall.IFF_MULTICAST
888
+		msg.Change |= unix.IFF_MULTICAST
889
+		msg.Flags |= unix.IFF_MULTICAST
853 890
 	}
891
+	if base.Index != 0 {
892
+		msg.Index = int32(base.Index)
893
+	}
894
+
854 895
 	req.AddData(msg)
855 896
 
856 897
 	if base.ParentIndex != 0 {
857 898
 		b := make([]byte, 4)
858 899
 		native.PutUint32(b, uint32(base.ParentIndex))
859
-		data := nl.NewRtAttr(syscall.IFLA_LINK, b)
900
+		data := nl.NewRtAttr(unix.IFLA_LINK, b)
860 901
 		req.AddData(data)
861 902
 	} else if link.Type() == "ipvlan" {
862 903
 		return fmt.Errorf("Can't create ipvlan link without ParentIndex")
863 904
 	}
864 905
 
865
-	nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(base.Name))
906
+	nameData := nl.NewRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(base.Name))
866 907
 	req.AddData(nameData)
867 908
 
868 909
 	if base.MTU > 0 {
869
-		mtu := nl.NewRtAttr(syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
910
+		mtu := nl.NewRtAttr(unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
870 911
 		req.AddData(mtu)
871 912
 	}
872 913
 
873 914
 	if base.TxQLen >= 0 {
874
-		qlen := nl.NewRtAttr(syscall.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
915
+		qlen := nl.NewRtAttr(unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
875 916
 		req.AddData(qlen)
876 917
 	}
877 918
 
878 919
 	if base.HardwareAddr != nil {
879
-		hwaddr := nl.NewRtAttr(syscall.IFLA_ADDRESS, []byte(base.HardwareAddr))
920
+		hwaddr := nl.NewRtAttr(unix.IFLA_ADDRESS, []byte(base.HardwareAddr))
880 921
 		req.AddData(hwaddr)
881 922
 	}
882 923
 
924
+	if base.NumTxQueues > 0 {
925
+		txqueues := nl.NewRtAttr(unix.IFLA_NUM_TX_QUEUES, nl.Uint32Attr(uint32(base.NumTxQueues)))
926
+		req.AddData(txqueues)
927
+	}
928
+
929
+	if base.NumRxQueues > 0 {
930
+		rxqueues := nl.NewRtAttr(unix.IFLA_NUM_RX_QUEUES, nl.Uint32Attr(uint32(base.NumRxQueues)))
931
+		req.AddData(rxqueues)
932
+	}
933
+
883 934
 	if base.Namespace != nil {
884 935
 		var attr *nl.RtAttr
885 936
 		switch base.Namespace.(type) {
886 937
 		case NsPid:
887 938
 			val := nl.Uint32Attr(uint32(base.Namespace.(NsPid)))
888
-			attr = nl.NewRtAttr(syscall.IFLA_NET_NS_PID, val)
939
+			attr = nl.NewRtAttr(unix.IFLA_NET_NS_PID, val)
889 940
 		case NsFd:
890 941
 			val := nl.Uint32Attr(uint32(base.Namespace.(NsFd)))
891
-			attr = nl.NewRtAttr(nl.IFLA_NET_NS_FD, val)
942
+			attr = nl.NewRtAttr(unix.IFLA_NET_NS_FD, val)
892 943
 		}
893 944
 
894 945
 		req.AddData(attr)
... ...
@@ -898,7 +1028,7 @@ func (h *Handle) linkModify(link Link, flags int) error {
898 898
 		addXdpAttrs(base.Xdp, req)
899 899
 	}
900 900
 
901
-	linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil)
901
+	linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil)
902 902
 	nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
903 903
 
904 904
 	switch link := link.(type) {
... ...
@@ -910,13 +1040,13 @@ func (h *Handle) linkModify(link Link, flags int) error {
910 910
 	case *Veth:
911 911
 		data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
912 912
 		peer := nl.NewRtAttrChild(data, nl.VETH_INFO_PEER, nil)
913
-		nl.NewIfInfomsgChild(peer, syscall.AF_UNSPEC)
914
-		nl.NewRtAttrChild(peer, syscall.IFLA_IFNAME, nl.ZeroTerminated(link.PeerName))
913
+		nl.NewIfInfomsgChild(peer, unix.AF_UNSPEC)
914
+		nl.NewRtAttrChild(peer, unix.IFLA_IFNAME, nl.ZeroTerminated(link.PeerName))
915 915
 		if base.TxQLen >= 0 {
916
-			nl.NewRtAttrChild(peer, syscall.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
916
+			nl.NewRtAttrChild(peer, unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
917 917
 		}
918 918
 		if base.MTU > 0 {
919
-			nl.NewRtAttrChild(peer, syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
919
+			nl.NewRtAttrChild(peer, unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
920 920
 		}
921 921
 
922 922
 	case *Vxlan:
... ...
@@ -940,6 +1070,8 @@ func (h *Handle) linkModify(link Link, flags int) error {
940 940
 		addGretapAttrs(link, linkInfo)
941 941
 	case *Iptun:
942 942
 		addIptunAttrs(link, linkInfo)
943
+	case *Sittun:
944
+		addSittunAttrs(link, linkInfo)
943 945
 	case *Gretun:
944 946
 		addGretunAttrs(link, linkInfo)
945 947
 	case *Vti:
... ...
@@ -954,7 +1086,7 @@ func (h *Handle) linkModify(link Link, flags int) error {
954 954
 
955 955
 	req.AddData(linkInfo)
956 956
 
957
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
957
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
958 958
 	if err != nil {
959 959
 		return err
960 960
 	}
... ...
@@ -984,13 +1116,13 @@ func (h *Handle) LinkDel(link Link) error {
984 984
 
985 985
 	h.ensureIndex(base)
986 986
 
987
-	req := h.newNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK)
987
+	req := h.newNetlinkRequest(unix.RTM_DELLINK, unix.NLM_F_ACK)
988 988
 
989
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
989
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
990 990
 	msg.Index = int32(base.Index)
991 991
 	req.AddData(msg)
992 992
 
993
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
993
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
994 994
 	return err
995 995
 }
996 996
 
... ...
@@ -1033,16 +1165,16 @@ func (h *Handle) LinkByName(name string) (Link, error) {
1033 1033
 		return h.linkByNameDump(name)
1034 1034
 	}
1035 1035
 
1036
-	req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK)
1036
+	req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_ACK)
1037 1037
 
1038
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
1038
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
1039 1039
 	req.AddData(msg)
1040 1040
 
1041
-	nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(name))
1041
+	nameData := nl.NewRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(name))
1042 1042
 	req.AddData(nameData)
1043 1043
 
1044 1044
 	link, err := execGetLink(req)
1045
-	if err == syscall.EINVAL {
1045
+	if err == unix.EINVAL {
1046 1046
 		// older kernels don't support looking up via IFLA_IFNAME
1047 1047
 		// so fall back to dumping all links
1048 1048
 		h.lookupByDump = true
... ...
@@ -1065,16 +1197,16 @@ func (h *Handle) LinkByAlias(alias string) (Link, error) {
1065 1065
 		return h.linkByAliasDump(alias)
1066 1066
 	}
1067 1067
 
1068
-	req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK)
1068
+	req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_ACK)
1069 1069
 
1070
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
1070
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
1071 1071
 	req.AddData(msg)
1072 1072
 
1073
-	nameData := nl.NewRtAttr(syscall.IFLA_IFALIAS, nl.ZeroTerminated(alias))
1073
+	nameData := nl.NewRtAttr(unix.IFLA_IFALIAS, nl.ZeroTerminated(alias))
1074 1074
 	req.AddData(nameData)
1075 1075
 
1076 1076
 	link, err := execGetLink(req)
1077
-	if err == syscall.EINVAL {
1077
+	if err == unix.EINVAL {
1078 1078
 		// older kernels don't support looking up via IFLA_IFALIAS
1079 1079
 		// so fall back to dumping all links
1080 1080
 		h.lookupByDump = true
... ...
@@ -1091,9 +1223,9 @@ func LinkByIndex(index int) (Link, error) {
1091 1091
 
1092 1092
 // LinkByIndex finds a link by index and returns a pointer to the object.
1093 1093
 func (h *Handle) LinkByIndex(index int) (Link, error) {
1094
-	req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK)
1094
+	req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_ACK)
1095 1095
 
1096
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
1096
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
1097 1097
 	msg.Index = int32(index)
1098 1098
 	req.AddData(msg)
1099 1099
 
... ...
@@ -1101,10 +1233,10 @@ func (h *Handle) LinkByIndex(index int) (Link, error) {
1101 1101
 }
1102 1102
 
1103 1103
 func execGetLink(req *nl.NetlinkRequest) (Link, error) {
1104
-	msgs, err := req.Execute(syscall.NETLINK_ROUTE, 0)
1104
+	msgs, err := req.Execute(unix.NETLINK_ROUTE, 0)
1105 1105
 	if err != nil {
1106 1106
 		if errno, ok := err.(syscall.Errno); ok {
1107
-			if errno == syscall.ENODEV {
1107
+			if errno == unix.ENODEV {
1108 1108
 				return nil, LinkNotFoundError{fmt.Errorf("Link not found")}
1109 1109
 			}
1110 1110
 		}
... ...
@@ -1125,7 +1257,7 @@ func execGetLink(req *nl.NetlinkRequest) (Link, error) {
1125 1125
 
1126 1126
 // linkDeserialize deserializes a raw message received from netlink into
1127 1127
 // a link object.
1128
-func LinkDeserialize(hdr *syscall.NlMsghdr, m []byte) (Link, error) {
1128
+func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
1129 1129
 	msg := nl.DeserializeIfInfomsg(m)
1130 1130
 
1131 1131
 	attrs, err := nl.ParseRouteAttr(m[msg.Len():])
... ...
@@ -1134,7 +1266,7 @@ func LinkDeserialize(hdr *syscall.NlMsghdr, m []byte) (Link, error) {
1134 1134
 	}
1135 1135
 
1136 1136
 	base := LinkAttrs{Index: int(msg.Index), RawFlags: msg.Flags, Flags: linkFlags(msg.Flags), EncapType: msg.EncapType()}
1137
-	if msg.Flags&syscall.IFF_PROMISC != 0 {
1137
+	if msg.Flags&unix.IFF_PROMISC != 0 {
1138 1138
 		base.Promisc = 1
1139 1139
 	}
1140 1140
 	var (
... ...
@@ -1145,7 +1277,7 @@ func LinkDeserialize(hdr *syscall.NlMsghdr, m []byte) (Link, error) {
1145 1145
 	)
1146 1146
 	for _, attr := range attrs {
1147 1147
 		switch attr.Attr.Type {
1148
-		case syscall.IFLA_LINKINFO:
1148
+		case unix.IFLA_LINKINFO:
1149 1149
 			infos, err := nl.ParseRouteAttr(attr.Value)
1150 1150
 			if err != nil {
1151 1151
 				return nil, err
... ...
@@ -1177,10 +1309,16 @@ func LinkDeserialize(hdr *syscall.NlMsghdr, m []byte) (Link, error) {
1177 1177
 						link = &Macvtap{}
1178 1178
 					case "gretap":
1179 1179
 						link = &Gretap{}
1180
+					case "ip6gretap":
1181
+						link = &Gretap{}
1180 1182
 					case "ipip":
1181 1183
 						link = &Iptun{}
1184
+					case "sit":
1185
+						link = &Sittun{}
1182 1186
 					case "gre":
1183 1187
 						link = &Gretun{}
1188
+					case "ip6gre":
1189
+						link = &Gretun{}
1184 1190
 					case "vti":
1185 1191
 						link = &Vti{}
1186 1192
 					case "vrf":
... ...
@@ -1210,10 +1348,16 @@ func LinkDeserialize(hdr *syscall.NlMsghdr, m []byte) (Link, error) {
1210 1210
 						parseMacvtapData(link, data)
1211 1211
 					case "gretap":
1212 1212
 						parseGretapData(link, data)
1213
+					case "ip6gretap":
1214
+						parseGretapData(link, data)
1213 1215
 					case "ipip":
1214 1216
 						parseIptunData(link, data)
1217
+					case "sit":
1218
+						parseSittunData(link, data)
1215 1219
 					case "gre":
1216 1220
 						parseGretunData(link, data)
1221
+					case "ip6gre":
1222
+						parseGretunData(link, data)
1217 1223
 					case "vti":
1218 1224
 						parseVtiData(link, data)
1219 1225
 					case "vrf":
... ...
@@ -1225,7 +1369,7 @@ func LinkDeserialize(hdr *syscall.NlMsghdr, m []byte) (Link, error) {
1225 1225
 					}
1226 1226
 				}
1227 1227
 			}
1228
-		case syscall.IFLA_ADDRESS:
1228
+		case unix.IFLA_ADDRESS:
1229 1229
 			var nonzero bool
1230 1230
 			for _, b := range attr.Value {
1231 1231
 				if b != 0 {
... ...
@@ -1235,40 +1379,40 @@ func LinkDeserialize(hdr *syscall.NlMsghdr, m []byte) (Link, error) {
1235 1235
 			if nonzero {
1236 1236
 				base.HardwareAddr = attr.Value[:]
1237 1237
 			}
1238
-		case syscall.IFLA_IFNAME:
1238
+		case unix.IFLA_IFNAME:
1239 1239
 			base.Name = string(attr.Value[:len(attr.Value)-1])
1240
-		case syscall.IFLA_MTU:
1240
+		case unix.IFLA_MTU:
1241 1241
 			base.MTU = int(native.Uint32(attr.Value[0:4]))
1242
-		case syscall.IFLA_LINK:
1242
+		case unix.IFLA_LINK:
1243 1243
 			base.ParentIndex = int(native.Uint32(attr.Value[0:4]))
1244
-		case syscall.IFLA_MASTER:
1244
+		case unix.IFLA_MASTER:
1245 1245
 			base.MasterIndex = int(native.Uint32(attr.Value[0:4]))
1246
-		case syscall.IFLA_TXQLEN:
1246
+		case unix.IFLA_TXQLEN:
1247 1247
 			base.TxQLen = int(native.Uint32(attr.Value[0:4]))
1248
-		case syscall.IFLA_IFALIAS:
1248
+		case unix.IFLA_IFALIAS:
1249 1249
 			base.Alias = string(attr.Value[:len(attr.Value)-1])
1250
-		case syscall.IFLA_STATS:
1250
+		case unix.IFLA_STATS:
1251 1251
 			stats32 = attr.Value[:]
1252
-		case IFLA_STATS64:
1252
+		case unix.IFLA_STATS64:
1253 1253
 			stats64 = attr.Value[:]
1254
-		case nl.IFLA_XDP:
1254
+		case unix.IFLA_XDP:
1255 1255
 			xdp, err := parseLinkXdp(attr.Value[:])
1256 1256
 			if err != nil {
1257 1257
 				return nil, err
1258 1258
 			}
1259 1259
 			base.Xdp = xdp
1260
-		case syscall.IFLA_PROTINFO | syscall.NLA_F_NESTED:
1261
-			if hdr != nil && hdr.Type == syscall.RTM_NEWLINK &&
1262
-				msg.Family == syscall.AF_BRIDGE {
1260
+		case unix.IFLA_PROTINFO | unix.NLA_F_NESTED:
1261
+			if hdr != nil && hdr.Type == unix.RTM_NEWLINK &&
1262
+				msg.Family == unix.AF_BRIDGE {
1263 1263
 				attrs, err := nl.ParseRouteAttr(attr.Value[:])
1264 1264
 				if err != nil {
1265 1265
 					return nil, err
1266 1266
 				}
1267 1267
 				base.Protinfo = parseProtinfo(attrs)
1268 1268
 			}
1269
-		case syscall.IFLA_OPERSTATE:
1269
+		case unix.IFLA_OPERSTATE:
1270 1270
 			base.OperState = LinkOperState(uint8(attr.Value[0]))
1271
-		case nl.IFLA_LINK_NETNSID:
1271
+		case unix.IFLA_LINK_NETNSID:
1272 1272
 			base.NetNsID = int(native.Uint32(attr.Value[0:4]))
1273 1273
 		}
1274 1274
 	}
... ...
@@ -1299,12 +1443,12 @@ func LinkList() ([]Link, error) {
1299 1299
 func (h *Handle) LinkList() ([]Link, error) {
1300 1300
 	// NOTE(vish): This duplicates functionality in net/iface_linux.go, but we need
1301 1301
 	//             to get the message ourselves to parse link type.
1302
-	req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP)
1302
+	req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
1303 1303
 
1304
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
1304
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
1305 1305
 	req.AddData(msg)
1306 1306
 
1307
-	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWLINK)
1307
+	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
1308 1308
 	if err != nil {
1309 1309
 		return nil, err
1310 1310
 	}
... ...
@@ -1324,20 +1468,20 @@ func (h *Handle) LinkList() ([]Link, error) {
1324 1324
 // LinkUpdate is used to pass information back from LinkSubscribe()
1325 1325
 type LinkUpdate struct {
1326 1326
 	nl.IfInfomsg
1327
-	Header syscall.NlMsghdr
1327
+	Header unix.NlMsghdr
1328 1328
 	Link
1329 1329
 }
1330 1330
 
1331 1331
 // LinkSubscribe takes a chan down which notifications will be sent
1332 1332
 // when links change.  Close the 'done' chan to stop subscription.
1333 1333
 func LinkSubscribe(ch chan<- LinkUpdate, done <-chan struct{}) error {
1334
-	return linkSubscribeAt(netns.None(), netns.None(), ch, done, nil)
1334
+	return linkSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
1335 1335
 }
1336 1336
 
1337 1337
 // LinkSubscribeAt works like LinkSubscribe plus it allows the caller
1338 1338
 // to choose the network namespace in which to subscribe (ns).
1339 1339
 func LinkSubscribeAt(ns netns.NsHandle, ch chan<- LinkUpdate, done <-chan struct{}) error {
1340
-	return linkSubscribeAt(ns, netns.None(), ch, done, nil)
1340
+	return linkSubscribeAt(ns, netns.None(), ch, done, nil, false)
1341 1341
 }
1342 1342
 
1343 1343
 // LinkSubscribeOptions contains a set of options to use with
... ...
@@ -1345,6 +1489,7 @@ func LinkSubscribeAt(ns netns.NsHandle, ch chan<- LinkUpdate, done <-chan struct
1345 1345
 type LinkSubscribeOptions struct {
1346 1346
 	Namespace     *netns.NsHandle
1347 1347
 	ErrorCallback func(error)
1348
+	ListExisting  bool
1348 1349
 }
1349 1350
 
1350 1351
 // LinkSubscribeWithOptions work like LinkSubscribe but enable to
... ...
@@ -1355,11 +1500,11 @@ func LinkSubscribeWithOptions(ch chan<- LinkUpdate, done <-chan struct{}, option
1355 1355
 		none := netns.None()
1356 1356
 		options.Namespace = &none
1357 1357
 	}
1358
-	return linkSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback)
1358
+	return linkSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
1359 1359
 }
1360 1360
 
1361
-func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-chan struct{}, cberr func(error)) error {
1362
-	s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_LINK)
1361
+func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
1362
+	s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_LINK)
1363 1363
 	if err != nil {
1364 1364
 		return err
1365 1365
 	}
... ...
@@ -1369,6 +1514,15 @@ func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-c
1369 1369
 			s.Close()
1370 1370
 		}()
1371 1371
 	}
1372
+	if listExisting {
1373
+		req := pkgHandle.newNetlinkRequest(unix.RTM_GETLINK,
1374
+			unix.NLM_F_DUMP)
1375
+		msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
1376
+		req.AddData(msg)
1377
+		if err := s.Send(req); err != nil {
1378
+			return err
1379
+		}
1380
+	}
1372 1381
 	go func() {
1373 1382
 		defer close(ch)
1374 1383
 		for {
... ...
@@ -1380,15 +1534,30 @@ func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-c
1380 1380
 				return
1381 1381
 			}
1382 1382
 			for _, m := range msgs {
1383
+				if m.Header.Type == unix.NLMSG_DONE {
1384
+					continue
1385
+				}
1386
+				if m.Header.Type == unix.NLMSG_ERROR {
1387
+					native := nl.NativeEndian()
1388
+					error := int32(native.Uint32(m.Data[0:4]))
1389
+					if error == 0 {
1390
+						continue
1391
+					}
1392
+					if cberr != nil {
1393
+						cberr(syscall.Errno(-error))
1394
+					}
1395
+					return
1396
+				}
1383 1397
 				ifmsg := nl.DeserializeIfInfomsg(m.Data)
1384
-				link, err := LinkDeserialize(&m.Header, m.Data)
1398
+				header := unix.NlMsghdr(m.Header)
1399
+				link, err := LinkDeserialize(&header, m.Data)
1385 1400
 				if err != nil {
1386 1401
 					if cberr != nil {
1387 1402
 						cberr(err)
1388 1403
 					}
1389 1404
 					return
1390 1405
 				}
1391
-				ch <- LinkUpdate{IfInfomsg: *ifmsg, Header: m.Header, Link: link}
1406
+				ch <- LinkUpdate{IfInfomsg: *ifmsg, Header: header, Link: link}
1392 1407
 			}
1393 1408
 		}
1394 1409
 	}()
... ...
@@ -1463,16 +1632,16 @@ func (h *Handle) LinkSetBrProxyArpWiFi(link Link, mode bool) error {
1463 1463
 func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
1464 1464
 	base := link.Attrs()
1465 1465
 	h.ensureIndex(base)
1466
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
1466
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
1467 1467
 
1468
-	msg := nl.NewIfInfomsg(syscall.AF_BRIDGE)
1468
+	msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
1469 1469
 	msg.Index = int32(base.Index)
1470 1470
 	req.AddData(msg)
1471 1471
 
1472
-	br := nl.NewRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil)
1472
+	br := nl.NewRtAttr(unix.IFLA_PROTINFO|unix.NLA_F_NESTED, nil)
1473 1473
 	nl.NewRtAttrChild(br, attr, boolToByte(mode))
1474 1474
 	req.AddData(br)
1475
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
1475
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
1476 1476
 	if err != nil {
1477 1477
 		return err
1478 1478
 	}
... ...
@@ -1490,19 +1659,19 @@ func LinkSetTxQLen(link Link, qlen int) error {
1490 1490
 func (h *Handle) LinkSetTxQLen(link Link, qlen int) error {
1491 1491
 	base := link.Attrs()
1492 1492
 	h.ensureIndex(base)
1493
-	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
1493
+	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
1494 1494
 
1495
-	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
1495
+	msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
1496 1496
 	msg.Index = int32(base.Index)
1497 1497
 	req.AddData(msg)
1498 1498
 
1499 1499
 	b := make([]byte, 4)
1500 1500
 	native.PutUint32(b, uint32(qlen))
1501 1501
 
1502
-	data := nl.NewRtAttr(syscall.IFLA_TXQLEN, b)
1502
+	data := nl.NewRtAttr(unix.IFLA_TXQLEN, b)
1503 1503
 	req.AddData(data)
1504 1504
 
1505
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
1505
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
1506 1506
 	return err
1507 1507
 }
1508 1508
 
... ...
@@ -1548,6 +1717,10 @@ func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
1548 1548
 			vxlan.L3miss = int8(datum.Value[0]) != 0
1549 1549
 		case nl.IFLA_VXLAN_UDP_CSUM:
1550 1550
 			vxlan.UDPCSum = int8(datum.Value[0]) != 0
1551
+		case nl.IFLA_VXLAN_UDP_ZERO_CSUM6_TX:
1552
+			vxlan.UDP6ZeroCSumTx = int8(datum.Value[0]) != 0
1553
+		case nl.IFLA_VXLAN_UDP_ZERO_CSUM6_RX:
1554
+			vxlan.UDP6ZeroCSumRx = int8(datum.Value[0]) != 0
1551 1555
 		case nl.IFLA_VXLAN_GBP:
1552 1556
 			vxlan.GBP = true
1553 1557
 		case nl.IFLA_VXLAN_FLOWBASED:
... ...
@@ -1650,7 +1823,8 @@ func parseMacvtapData(link Link, data []syscall.NetlinkRouteAttr) {
1650 1650
 func parseMacvlanData(link Link, data []syscall.NetlinkRouteAttr) {
1651 1651
 	macv := link.(*Macvlan)
1652 1652
 	for _, datum := range data {
1653
-		if datum.Attr.Type == nl.IFLA_MACVLAN_MODE {
1653
+		switch datum.Attr.Type {
1654
+		case nl.IFLA_MACVLAN_MODE:
1654 1655
 			switch native.Uint32(datum.Value[0:4]) {
1655 1656
 			case nl.MACVLAN_MODE_PRIVATE:
1656 1657
 				macv.Mode = MACVLAN_MODE_PRIVATE
... ...
@@ -1663,7 +1837,16 @@ func parseMacvlanData(link Link, data []syscall.NetlinkRouteAttr) {
1663 1663
 			case nl.MACVLAN_MODE_SOURCE:
1664 1664
 				macv.Mode = MACVLAN_MODE_SOURCE
1665 1665
 			}
1666
-			return
1666
+		case nl.IFLA_MACVLAN_MACADDR_COUNT:
1667
+			macv.MACAddrs = make([]net.HardwareAddr, 0, int(native.Uint32(datum.Value[0:4])))
1668
+		case nl.IFLA_MACVLAN_MACADDR_DATA:
1669
+			macs, err := nl.ParseRouteAttr(datum.Value[:])
1670
+			if err != nil {
1671
+				panic(fmt.Sprintf("failed to ParseRouteAttr for IFLA_MACVLAN_MACADDR_DATA: %v", err))
1672
+			}
1673
+			for _, macDatum := range macs {
1674
+				macv.MACAddrs = append(macv.MACAddrs, net.HardwareAddr(macDatum.Value[0:6]))
1675
+			}
1667 1676
 		}
1668 1677
 	}
1669 1678
 }
... ...
@@ -1671,19 +1854,19 @@ func parseMacvlanData(link Link, data []syscall.NetlinkRouteAttr) {
1671 1671
 // copied from pkg/net_linux.go
1672 1672
 func linkFlags(rawFlags uint32) net.Flags {
1673 1673
 	var f net.Flags
1674
-	if rawFlags&syscall.IFF_UP != 0 {
1674
+	if rawFlags&unix.IFF_UP != 0 {
1675 1675
 		f |= net.FlagUp
1676 1676
 	}
1677
-	if rawFlags&syscall.IFF_BROADCAST != 0 {
1677
+	if rawFlags&unix.IFF_BROADCAST != 0 {
1678 1678
 		f |= net.FlagBroadcast
1679 1679
 	}
1680
-	if rawFlags&syscall.IFF_LOOPBACK != 0 {
1680
+	if rawFlags&unix.IFF_LOOPBACK != 0 {
1681 1681
 		f |= net.FlagLoopback
1682 1682
 	}
1683
-	if rawFlags&syscall.IFF_POINTOPOINT != 0 {
1683
+	if rawFlags&unix.IFF_POINTOPOINT != 0 {
1684 1684
 		f |= net.FlagPointToPoint
1685 1685
 	}
1686
-	if rawFlags&syscall.IFF_MULTICAST != 0 {
1686
+	if rawFlags&unix.IFF_MULTICAST != 0 {
1687 1687
 		f |= net.FlagMulticast
1688 1688
 	}
1689 1689
 	return f
... ...
@@ -1698,12 +1881,17 @@ func addGretapAttrs(gretap *Gretap, linkInfo *nl.RtAttr) {
1698 1698
 		return
1699 1699
 	}
1700 1700
 
1701
-	ip := gretap.Local.To4()
1702
-	if ip != nil {
1701
+	if ip := gretap.Local; ip != nil {
1702
+		if ip.To4() != nil {
1703
+			ip = ip.To4()
1704
+		}
1703 1705
 		nl.NewRtAttrChild(data, nl.IFLA_GRE_LOCAL, []byte(ip))
1704 1706
 	}
1705
-	ip = gretap.Remote.To4()
1706
-	if ip != nil {
1707
+
1708
+	if ip := gretap.Remote; ip != nil {
1709
+		if ip.To4() != nil {
1710
+			ip = ip.To4()
1711
+		}
1707 1712
 		nl.NewRtAttrChild(data, nl.IFLA_GRE_REMOTE, []byte(ip))
1708 1713
 	}
1709 1714
 
... ...
@@ -1742,9 +1930,9 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) {
1742 1742
 		case nl.IFLA_GRE_IKEY:
1743 1743
 			gre.OKey = ntohl(datum.Value[0:4])
1744 1744
 		case nl.IFLA_GRE_LOCAL:
1745
-			gre.Local = net.IP(datum.Value[0:4])
1745
+			gre.Local = net.IP(datum.Value[0:16])
1746 1746
 		case nl.IFLA_GRE_REMOTE:
1747
-			gre.Remote = net.IP(datum.Value[0:4])
1747
+			gre.Remote = net.IP(datum.Value[0:16])
1748 1748
 		case nl.IFLA_GRE_ENCAP_SPORT:
1749 1749
 			gre.EncapSport = ntohs(datum.Value[0:2])
1750 1750
 		case nl.IFLA_GRE_ENCAP_DPORT:
... ...
@@ -1765,7 +1953,9 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) {
1765 1765
 		case nl.IFLA_GRE_ENCAP_FLAGS:
1766 1766
 			gre.EncapFlags = native.Uint16(datum.Value[0:2])
1767 1767
 		case nl.IFLA_GRE_COLLECT_METADATA:
1768
-			gre.FlowBased = int8(datum.Value[0]) != 0
1768
+			if len(datum.Value) > 0 {
1769
+				gre.FlowBased = int8(datum.Value[0]) != 0
1770
+			}
1769 1771
 		}
1770 1772
 	}
1771 1773
 }
... ...
@@ -1773,12 +1963,17 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) {
1773 1773
 func addGretunAttrs(gre *Gretun, linkInfo *nl.RtAttr) {
1774 1774
 	data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
1775 1775
 
1776
-	ip := gre.Local.To4()
1777
-	if ip != nil {
1776
+	if ip := gre.Local; ip != nil {
1777
+		if ip.To4() != nil {
1778
+			ip = ip.To4()
1779
+		}
1778 1780
 		nl.NewRtAttrChild(data, nl.IFLA_GRE_LOCAL, []byte(ip))
1779 1781
 	}
1780
-	ip = gre.Remote.To4()
1781
-	if ip != nil {
1782
+
1783
+	if ip := gre.Remote; ip != nil {
1784
+		if ip.To4() != nil {
1785
+			ip = ip.To4()
1786
+		}
1782 1787
 		nl.NewRtAttrChild(data, nl.IFLA_GRE_REMOTE, []byte(ip))
1783 1788
 	}
1784 1789
 
... ...
@@ -1802,6 +1997,10 @@ func addGretunAttrs(gre *Gretun, linkInfo *nl.RtAttr) {
1802 1802
 	nl.NewRtAttrChild(data, nl.IFLA_GRE_PMTUDISC, nl.Uint8Attr(gre.PMtuDisc))
1803 1803
 	nl.NewRtAttrChild(data, nl.IFLA_GRE_TTL, nl.Uint8Attr(gre.Ttl))
1804 1804
 	nl.NewRtAttrChild(data, nl.IFLA_GRE_TOS, nl.Uint8Attr(gre.Tos))
1805
+	nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_TYPE, nl.Uint16Attr(gre.EncapType))
1806
+	nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_FLAGS, nl.Uint16Attr(gre.EncapFlags))
1807
+	nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_SPORT, htons(gre.EncapSport))
1808
+	nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_DPORT, htons(gre.EncapDport))
1805 1809
 }
1806 1810
 
1807 1811
 func parseGretunData(link Link, data []syscall.NetlinkRouteAttr) {
... ...
@@ -1813,9 +2012,9 @@ func parseGretunData(link Link, data []syscall.NetlinkRouteAttr) {
1813 1813
 		case nl.IFLA_GRE_IKEY:
1814 1814
 			gre.OKey = ntohl(datum.Value[0:4])
1815 1815
 		case nl.IFLA_GRE_LOCAL:
1816
-			gre.Local = net.IP(datum.Value[0:4])
1816
+			gre.Local = net.IP(datum.Value[0:16])
1817 1817
 		case nl.IFLA_GRE_REMOTE:
1818
-			gre.Remote = net.IP(datum.Value[0:4])
1818
+			gre.Remote = net.IP(datum.Value[0:16])
1819 1819
 		case nl.IFLA_GRE_IFLAGS:
1820 1820
 			gre.IFlags = ntohs(datum.Value[0:2])
1821 1821
 		case nl.IFLA_GRE_OFLAGS:
... ...
@@ -1827,6 +2026,14 @@ func parseGretunData(link Link, data []syscall.NetlinkRouteAttr) {
1827 1827
 			gre.Tos = uint8(datum.Value[0])
1828 1828
 		case nl.IFLA_GRE_PMTUDISC:
1829 1829
 			gre.PMtuDisc = uint8(datum.Value[0])
1830
+		case nl.IFLA_GRE_ENCAP_TYPE:
1831
+			gre.EncapType = native.Uint16(datum.Value[0:2])
1832
+		case nl.IFLA_GRE_ENCAP_FLAGS:
1833
+			gre.EncapFlags = native.Uint16(datum.Value[0:2])
1834
+		case nl.IFLA_GRE_ENCAP_SPORT:
1835
+			gre.EncapSport = ntohs(datum.Value[0:2])
1836
+		case nl.IFLA_GRE_ENCAP_DPORT:
1837
+			gre.EncapDport = ntohs(datum.Value[0:2])
1830 1838
 		}
1831 1839
 	}
1832 1840
 }
... ...
@@ -1840,11 +2047,12 @@ func parseLinkStats64(data []byte) *LinkStatistics {
1840 1840
 }
1841 1841
 
1842 1842
 func addXdpAttrs(xdp *LinkXdp, req *nl.NetlinkRequest) {
1843
-	attrs := nl.NewRtAttr(nl.IFLA_XDP|syscall.NLA_F_NESTED, nil)
1843
+	attrs := nl.NewRtAttr(unix.IFLA_XDP|unix.NLA_F_NESTED, nil)
1844 1844
 	b := make([]byte, 4)
1845 1845
 	native.PutUint32(b, uint32(xdp.Fd))
1846 1846
 	nl.NewRtAttrChild(attrs, nl.IFLA_XDP_FD, b)
1847 1847
 	if xdp.Flags != 0 {
1848
+		b := make([]byte, 4)
1848 1849
 		native.PutUint32(b, xdp.Flags)
1849 1850
 		nl.NewRtAttrChild(attrs, nl.IFLA_XDP_FLAGS, b)
1850 1851
 	}
... ...
@@ -1873,6 +2081,12 @@ func parseLinkXdp(data []byte) (*LinkXdp, error) {
1873 1873
 }
1874 1874
 
1875 1875
 func addIptunAttrs(iptun *Iptun, linkInfo *nl.RtAttr) {
1876
+	if iptun.FlowBased {
1877
+		// In flow based mode, no other attributes need to be configured
1878
+		nl.NewRtAttrChild(linkInfo, nl.IFLA_IPTUN_COLLECT_METADATA, boolAttr(iptun.FlowBased))
1879
+		return
1880
+	}
1881
+
1876 1882
 	data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
1877 1883
 
1878 1884
 	ip := iptun.Local.To4()
... ...
@@ -1891,6 +2105,10 @@ func addIptunAttrs(iptun *Iptun, linkInfo *nl.RtAttr) {
1891 1891
 	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(iptun.PMtuDisc))
1892 1892
 	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TTL, nl.Uint8Attr(iptun.Ttl))
1893 1893
 	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TOS, nl.Uint8Attr(iptun.Tos))
1894
+	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(iptun.EncapType))
1895
+	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(iptun.EncapFlags))
1896
+	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_SPORT, htons(iptun.EncapSport))
1897
+	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_DPORT, htons(iptun.EncapDport))
1894 1898
 }
1895 1899
 
1896 1900
 func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) {
... ...
@@ -1907,6 +2125,72 @@ func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) {
1907 1907
 			iptun.Tos = uint8(datum.Value[0])
1908 1908
 		case nl.IFLA_IPTUN_PMTUDISC:
1909 1909
 			iptun.PMtuDisc = uint8(datum.Value[0])
1910
+		case nl.IFLA_IPTUN_ENCAP_SPORT:
1911
+			iptun.EncapSport = ntohs(datum.Value[0:2])
1912
+		case nl.IFLA_IPTUN_ENCAP_DPORT:
1913
+			iptun.EncapDport = ntohs(datum.Value[0:2])
1914
+		case nl.IFLA_IPTUN_ENCAP_TYPE:
1915
+			iptun.EncapType = native.Uint16(datum.Value[0:2])
1916
+		case nl.IFLA_IPTUN_ENCAP_FLAGS:
1917
+			iptun.EncapFlags = native.Uint16(datum.Value[0:2])
1918
+		case nl.IFLA_IPTUN_COLLECT_METADATA:
1919
+			iptun.FlowBased = int8(datum.Value[0]) != 0
1920
+		}
1921
+	}
1922
+}
1923
+
1924
+func addSittunAttrs(sittun *Sittun, linkInfo *nl.RtAttr) {
1925
+	data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
1926
+
1927
+	if sittun.Link != 0 {
1928
+		nl.NewRtAttrChild(data, nl.IFLA_IPTUN_LINK, nl.Uint32Attr(sittun.Link))
1929
+	}
1930
+
1931
+	ip := sittun.Local.To4()
1932
+	if ip != nil {
1933
+		nl.NewRtAttrChild(data, nl.IFLA_IPTUN_LOCAL, []byte(ip))
1934
+	}
1935
+
1936
+	ip = sittun.Remote.To4()
1937
+	if ip != nil {
1938
+		nl.NewRtAttrChild(data, nl.IFLA_IPTUN_REMOTE, []byte(ip))
1939
+	}
1940
+
1941
+	if sittun.Ttl > 0 {
1942
+		// Would otherwise fail on 3.10 kernel
1943
+		nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TTL, nl.Uint8Attr(sittun.Ttl))
1944
+	}
1945
+
1946
+	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TOS, nl.Uint8Attr(sittun.Tos))
1947
+	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(sittun.PMtuDisc))
1948
+	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(sittun.EncapType))
1949
+	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(sittun.EncapFlags))
1950
+	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_SPORT, htons(sittun.EncapSport))
1951
+	nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_DPORT, htons(sittun.EncapDport))
1952
+}
1953
+
1954
+func parseSittunData(link Link, data []syscall.NetlinkRouteAttr) {
1955
+	sittun := link.(*Sittun)
1956
+	for _, datum := range data {
1957
+		switch datum.Attr.Type {
1958
+		case nl.IFLA_IPTUN_LOCAL:
1959
+			sittun.Local = net.IP(datum.Value[0:4])
1960
+		case nl.IFLA_IPTUN_REMOTE:
1961
+			sittun.Remote = net.IP(datum.Value[0:4])
1962
+		case nl.IFLA_IPTUN_TTL:
1963
+			sittun.Ttl = uint8(datum.Value[0])
1964
+		case nl.IFLA_IPTUN_TOS:
1965
+			sittun.Tos = uint8(datum.Value[0])
1966
+		case nl.IFLA_IPTUN_PMTUDISC:
1967
+			sittun.PMtuDisc = uint8(datum.Value[0])
1968
+		case nl.IFLA_IPTUN_ENCAP_TYPE:
1969
+			sittun.EncapType = native.Uint16(datum.Value[0:2])
1970
+		case nl.IFLA_IPTUN_ENCAP_FLAGS:
1971
+			sittun.EncapFlags = native.Uint16(datum.Value[0:2])
1972
+		case nl.IFLA_IPTUN_ENCAP_SPORT:
1973
+			sittun.EncapSport = ntohs(datum.Value[0:2])
1974
+		case nl.IFLA_IPTUN_ENCAP_DPORT:
1975
+			sittun.EncapDport = ntohs(datum.Value[0:2])
1910 1976
 		}
1911 1977
 	}
1912 1978
 }
... ...
@@ -2014,3 +2298,57 @@ func parseGTPData(link Link, data []syscall.NetlinkRouteAttr) {
2014 2014
 		}
2015 2015
 	}
2016 2016
 }
2017
+
2018
+// LinkSetBondSlave add slave to bond link via ioctl interface.
2019
+func LinkSetBondSlave(link Link, master *Bond) error {
2020
+	fd, err := getSocketUDP()
2021
+	if err != nil {
2022
+		return err
2023
+	}
2024
+	defer syscall.Close(fd)
2025
+
2026
+	ifreq := newIocltSlaveReq(link.Attrs().Name, master.Attrs().Name)
2027
+
2028
+	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), unix.SIOCBONDENSLAVE, uintptr(unsafe.Pointer(ifreq)))
2029
+	if errno != 0 {
2030
+		return fmt.Errorf("Failed to enslave %q to %q, errno=%v", link.Attrs().Name, master.Attrs().Name, errno)
2031
+	}
2032
+	return nil
2033
+}
2034
+
2035
+// VethPeerIndex get veth peer index.
2036
+func VethPeerIndex(link *Veth) (int, error) {
2037
+	fd, err := getSocketUDP()
2038
+	if err != nil {
2039
+		return -1, err
2040
+	}
2041
+	defer syscall.Close(fd)
2042
+
2043
+	ifreq, sSet := newIocltStringSetReq(link.Name)
2044
+	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), SIOCETHTOOL, uintptr(unsafe.Pointer(ifreq)))
2045
+	if errno != 0 {
2046
+		return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno)
2047
+	}
2048
+
2049
+	gstrings := &ethtoolGstrings{
2050
+		cmd:       ETHTOOL_GSTRINGS,
2051
+		stringSet: ETH_SS_STATS,
2052
+		length:    sSet.data[0],
2053
+	}
2054
+	ifreq.Data = uintptr(unsafe.Pointer(gstrings))
2055
+	_, _, errno = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), SIOCETHTOOL, uintptr(unsafe.Pointer(ifreq)))
2056
+	if errno != 0 {
2057
+		return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno)
2058
+	}
2059
+
2060
+	stats := &ethtoolStats{
2061
+		cmd:    ETHTOOL_GSTATS,
2062
+		nStats: gstrings.length,
2063
+	}
2064
+	ifreq.Data = uintptr(unsafe.Pointer(stats))
2065
+	_, _, errno = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), SIOCETHTOOL, uintptr(unsafe.Pointer(ifreq)))
2066
+	if errno != 0 {
2067
+		return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno)
2068
+	}
2069
+	return int(stats.data[0]), nil
2070
+}
... ...
@@ -15,6 +15,8 @@ type Neigh struct {
15 15
 	IP           net.IP
16 16
 	HardwareAddr net.HardwareAddr
17 17
 	LLIPAddr     net.IP //Used in the case of NHRP
18
+	Vlan         int
19
+	VNI          int
18 20
 }
19 21
 
20 22
 // String returns $ip/$hwaddr $label
... ...
@@ -2,10 +2,10 @@ package netlink
2 2
 
3 3
 import (
4 4
 	"net"
5
-	"syscall"
6 5
 	"unsafe"
7 6
 
8 7
 	"github.com/vishvananda/netlink/nl"
8
+	"golang.org/x/sys/unix"
9 9
 )
10 10
 
11 11
 const (
... ...
@@ -73,7 +73,7 @@ func NeighAdd(neigh *Neigh) error {
73 73
 // NeighAdd will add an IP to MAC mapping to the ARP table
74 74
 // Equivalent to: `ip neigh add ....`
75 75
 func (h *Handle) NeighAdd(neigh *Neigh) error {
76
-	return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL)
76
+	return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_EXCL)
77 77
 }
78 78
 
79 79
 // NeighSet will add or replace an IP to MAC mapping to the ARP table
... ...
@@ -85,7 +85,7 @@ func NeighSet(neigh *Neigh) error {
85 85
 // NeighSet will add or replace an IP to MAC mapping to the ARP table
86 86
 // Equivalent to: `ip neigh replace....`
87 87
 func (h *Handle) NeighSet(neigh *Neigh) error {
88
-	return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE)
88
+	return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_REPLACE)
89 89
 }
90 90
 
91 91
 // NeighAppend will append an entry to FDB
... ...
@@ -97,7 +97,7 @@ func NeighAppend(neigh *Neigh) error {
97 97
 // NeighAppend will append an entry to FDB
98 98
 // Equivalent to: `bridge fdb append...`
99 99
 func (h *Handle) NeighAppend(neigh *Neigh) error {
100
-	return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_APPEND)
100
+	return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_APPEND)
101 101
 }
102 102
 
103 103
 // NeighAppend will append an entry to FDB
... ...
@@ -109,7 +109,7 @@ func neighAdd(neigh *Neigh, mode int) error {
109 109
 // NeighAppend will append an entry to FDB
110 110
 // Equivalent to: `bridge fdb append...`
111 111
 func (h *Handle) neighAdd(neigh *Neigh, mode int) error {
112
-	req := h.newNetlinkRequest(syscall.RTM_NEWNEIGH, mode|syscall.NLM_F_ACK)
112
+	req := h.newNetlinkRequest(unix.RTM_NEWNEIGH, mode|unix.NLM_F_ACK)
113 113
 	return neighHandle(neigh, req)
114 114
 }
115 115
 
... ...
@@ -122,7 +122,7 @@ func NeighDel(neigh *Neigh) error {
122 122
 // NeighDel will delete an IP address from a link device.
123 123
 // Equivalent to: `ip addr del $addr dev $link`
124 124
 func (h *Handle) NeighDel(neigh *Neigh) error {
125
-	req := h.newNetlinkRequest(syscall.RTM_DELNEIGH, syscall.NLM_F_ACK)
125
+	req := h.newNetlinkRequest(unix.RTM_DELNEIGH, unix.NLM_F_ACK)
126 126
 	return neighHandle(neigh, req)
127 127
 }
128 128
 
... ...
@@ -160,7 +160,17 @@ func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
160 160
 		req.AddData(hwData)
161 161
 	}
162 162
 
163
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
163
+	if neigh.Vlan != 0 {
164
+		vlanData := nl.NewRtAttr(NDA_VLAN, nl.Uint16Attr(uint16(neigh.Vlan)))
165
+		req.AddData(vlanData)
166
+	}
167
+
168
+	if neigh.VNI != 0 {
169
+		vniData := nl.NewRtAttr(NDA_VNI, nl.Uint32Attr(uint32(neigh.VNI)))
170
+		req.AddData(vniData)
171
+	}
172
+
173
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
164 174
 	return err
165 175
 }
166 176
 
... ...
@@ -193,7 +203,7 @@ func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
193 193
 }
194 194
 
195 195
 func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) {
196
-	req := h.newNetlinkRequest(syscall.RTM_GETNEIGH, syscall.NLM_F_DUMP)
196
+	req := h.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP)
197 197
 	msg := Ndmsg{
198 198
 		Family: uint8(family),
199 199
 		Index:  uint32(linkIndex),
... ...
@@ -201,7 +211,7 @@ func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) {
201 201
 	}
202 202
 	req.AddData(&msg)
203 203
 
204
-	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWNEIGH)
204
+	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH)
205 205
 	if err != nil {
206 206
 		return nil, err
207 207
 	}
... ...
@@ -257,7 +267,7 @@ func NeighDeserialize(m []byte) (*Neigh, error) {
257 257
 			// BUG: Is this a bug in the netlink library?
258 258
 			// #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
259 259
 			// #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
260
-			attrLen := attr.Attr.Len - syscall.SizeofRtAttr
260
+			attrLen := attr.Attr.Len - unix.SizeofRtAttr
261 261
 			if attrLen == 4 && (encapType == "ipip" ||
262 262
 				encapType == "sit" ||
263 263
 				encapType == "gre") {
... ...
@@ -268,6 +278,10 @@ func NeighDeserialize(m []byte) (*Neigh, error) {
268 268
 			} else {
269 269
 				neigh.HardwareAddr = net.HardwareAddr(attr.Value)
270 270
 			}
271
+		case NDA_VLAN:
272
+			neigh.Vlan = int(native.Uint16(attr.Value[0:2]))
273
+		case NDA_VNI:
274
+			neigh.VNI = int(native.Uint32(attr.Value[0:4]))
271 275
 		}
272 276
 	}
273 277
 
... ...
@@ -1,17 +1,18 @@
1 1
 package nl
2 2
 
3 3
 import (
4
-	"syscall"
5 4
 	"unsafe"
5
+
6
+	"golang.org/x/sys/unix"
6 7
 )
7 8
 
8 9
 type IfAddrmsg struct {
9
-	syscall.IfAddrmsg
10
+	unix.IfAddrmsg
10 11
 }
11 12
 
12 13
 func NewIfAddrmsg(family int) *IfAddrmsg {
13 14
 	return &IfAddrmsg{
14
-		IfAddrmsg: syscall.IfAddrmsg{
15
+		IfAddrmsg: unix.IfAddrmsg{
15 16
 			Family: uint8(family),
16 17
 		},
17 18
 	}
... ...
@@ -35,15 +36,15 @@ func NewIfAddrmsg(family int) *IfAddrmsg {
35 35
 // SizeofIfAddrmsg     = 0x8
36 36
 
37 37
 func DeserializeIfAddrmsg(b []byte) *IfAddrmsg {
38
-	return (*IfAddrmsg)(unsafe.Pointer(&b[0:syscall.SizeofIfAddrmsg][0]))
38
+	return (*IfAddrmsg)(unsafe.Pointer(&b[0:unix.SizeofIfAddrmsg][0]))
39 39
 }
40 40
 
41 41
 func (msg *IfAddrmsg) Serialize() []byte {
42
-	return (*(*[syscall.SizeofIfAddrmsg]byte)(unsafe.Pointer(msg)))[:]
42
+	return (*(*[unix.SizeofIfAddrmsg]byte)(unsafe.Pointer(msg)))[:]
43 43
 }
44 44
 
45 45
 func (msg *IfAddrmsg) Len() int {
46
-	return syscall.SizeofIfAddrmsg
46
+	return unix.SizeofIfAddrmsg
47 47
 }
48 48
 
49 49
 // struct ifa_cacheinfo {
... ...
@@ -1,35 +1,11 @@
1 1
 package nl
2 2
 
3 3
 import (
4
-	"syscall"
5 4
 	"unsafe"
6 5
 )
7 6
 
8 7
 const (
9 8
 	DEFAULT_CHANGE = 0xFFFFFFFF
10
-	// doesn't exist in syscall
11
-	IFLA_VFINFO_LIST = syscall.IFLA_IFALIAS + 1 + iota
12
-	IFLA_STATS64
13
-	IFLA_VF_PORTS
14
-	IFLA_PORT_SELF
15
-	IFLA_AF_SPEC
16
-	IFLA_GROUP
17
-	IFLA_NET_NS_FD
18
-	IFLA_EXT_MASK
19
-	IFLA_PROMISCUITY
20
-	IFLA_NUM_TX_QUEUES
21
-	IFLA_NUM_RX_QUEUES
22
-	IFLA_CARRIER
23
-	IFLA_PHYS_PORT_ID
24
-	IFLA_CARRIER_CHANGES
25
-	IFLA_PHYS_SWITCH_ID
26
-	IFLA_LINK_NETNSID
27
-	IFLA_PHYS_PORT_NAME
28
-	IFLA_PROTO_DOWN
29
-	IFLA_GSO_MAX_SEGS
30
-	IFLA_GSO_MAX_SIZE
31
-	IFLA_PAD
32
-	IFLA_XDP
33 9
 )
34 10
 
35 11
 const (
... ...
@@ -118,6 +94,10 @@ const (
118 118
 	IFLA_MACVLAN_UNSPEC = iota
119 119
 	IFLA_MACVLAN_MODE
120 120
 	IFLA_MACVLAN_FLAGS
121
+	IFLA_MACVLAN_MACADDR_MODE
122
+	IFLA_MACVLAN_MACADDR
123
+	IFLA_MACVLAN_MACADDR_DATA
124
+	IFLA_MACVLAN_MACADDR_COUNT
121 125
 	IFLA_MACVLAN_MAX = IFLA_MACVLAN_FLAGS
122 126
 )
123 127
 
... ...
@@ -130,6 +110,13 @@ const (
130 130
 )
131 131
 
132 132
 const (
133
+	MACVLAN_MACADDR_ADD = iota
134
+	MACVLAN_MACADDR_DEL
135
+	MACVLAN_MACADDR_FLUSH
136
+	MACVLAN_MACADDR_SET
137
+)
138
+
139
+const (
133 140
 	IFLA_BOND_UNSPEC = iota
134 141
 	IFLA_BOND_MODE
135 142
 	IFLA_BOND_ACTIVE_SLAVE
... ...
@@ -475,7 +462,12 @@ const (
475 475
 	IFLA_IPTUN_6RD_RELAY_PREFIX
476 476
 	IFLA_IPTUN_6RD_PREFIXLEN
477 477
 	IFLA_IPTUN_6RD_RELAY_PREFIXLEN
478
-	IFLA_IPTUN_MAX = IFLA_IPTUN_6RD_RELAY_PREFIXLEN
478
+	IFLA_IPTUN_ENCAP_TYPE
479
+	IFLA_IPTUN_ENCAP_FLAGS
480
+	IFLA_IPTUN_ENCAP_SPORT
481
+	IFLA_IPTUN_ENCAP_DPORT
482
+	IFLA_IPTUN_COLLECT_METADATA
483
+	IFLA_IPTUN_MAX = IFLA_IPTUN_COLLECT_METADATA
479 484
 )
480 485
 
481 486
 const (
... ...
@@ -13,18 +13,19 @@ import (
13 13
 	"unsafe"
14 14
 
15 15
 	"github.com/vishvananda/netns"
16
+	"golang.org/x/sys/unix"
16 17
 )
17 18
 
18 19
 const (
19 20
 	// Family type definitions
20
-	FAMILY_ALL  = syscall.AF_UNSPEC
21
-	FAMILY_V4   = syscall.AF_INET
22
-	FAMILY_V6   = syscall.AF_INET6
21
+	FAMILY_ALL  = unix.AF_UNSPEC
22
+	FAMILY_V4   = unix.AF_INET
23
+	FAMILY_V6   = unix.AF_INET6
23 24
 	FAMILY_MPLS = AF_MPLS
24 25
 )
25 26
 
26 27
 // SupportedNlFamilies contains the list of netlink families this netlink package supports
27
-var SupportedNlFamilies = []int{syscall.NETLINK_ROUTE, syscall.NETLINK_XFRM, syscall.NETLINK_NETFILTER}
28
+var SupportedNlFamilies = []int{unix.NETLINK_ROUTE, unix.NETLINK_XFRM, unix.NETLINK_NETFILTER}
28 29
 
29 30
 var nextSeqNr uint32
30 31
 
... ...
@@ -77,161 +78,161 @@ type NetlinkRequestData interface {
77 77
 
78 78
 // IfInfomsg is related to links, but it is used for list requests as well
79 79
 type IfInfomsg struct {
80
-	syscall.IfInfomsg
80
+	unix.IfInfomsg
81 81
 }
82 82
 
83 83
 // Create an IfInfomsg with family specified
84 84
 func NewIfInfomsg(family int) *IfInfomsg {
85 85
 	return &IfInfomsg{
86
-		IfInfomsg: syscall.IfInfomsg{
86
+		IfInfomsg: unix.IfInfomsg{
87 87
 			Family: uint8(family),
88 88
 		},
89 89
 	}
90 90
 }
91 91
 
92 92
 func DeserializeIfInfomsg(b []byte) *IfInfomsg {
93
-	return (*IfInfomsg)(unsafe.Pointer(&b[0:syscall.SizeofIfInfomsg][0]))
93
+	return (*IfInfomsg)(unsafe.Pointer(&b[0:unix.SizeofIfInfomsg][0]))
94 94
 }
95 95
 
96 96
 func (msg *IfInfomsg) Serialize() []byte {
97
-	return (*(*[syscall.SizeofIfInfomsg]byte)(unsafe.Pointer(msg)))[:]
97
+	return (*(*[unix.SizeofIfInfomsg]byte)(unsafe.Pointer(msg)))[:]
98 98
 }
99 99
 
100 100
 func (msg *IfInfomsg) Len() int {
101
-	return syscall.SizeofIfInfomsg
101
+	return unix.SizeofIfInfomsg
102 102
 }
103 103
 
104 104
 func (msg *IfInfomsg) EncapType() string {
105 105
 	switch msg.Type {
106 106
 	case 0:
107 107
 		return "generic"
108
-	case syscall.ARPHRD_ETHER:
108
+	case unix.ARPHRD_ETHER:
109 109
 		return "ether"
110
-	case syscall.ARPHRD_EETHER:
110
+	case unix.ARPHRD_EETHER:
111 111
 		return "eether"
112
-	case syscall.ARPHRD_AX25:
112
+	case unix.ARPHRD_AX25:
113 113
 		return "ax25"
114
-	case syscall.ARPHRD_PRONET:
114
+	case unix.ARPHRD_PRONET:
115 115
 		return "pronet"
116
-	case syscall.ARPHRD_CHAOS:
116
+	case unix.ARPHRD_CHAOS:
117 117
 		return "chaos"
118
-	case syscall.ARPHRD_IEEE802:
118
+	case unix.ARPHRD_IEEE802:
119 119
 		return "ieee802"
120
-	case syscall.ARPHRD_ARCNET:
120
+	case unix.ARPHRD_ARCNET:
121 121
 		return "arcnet"
122
-	case syscall.ARPHRD_APPLETLK:
122
+	case unix.ARPHRD_APPLETLK:
123 123
 		return "atalk"
124
-	case syscall.ARPHRD_DLCI:
124
+	case unix.ARPHRD_DLCI:
125 125
 		return "dlci"
126
-	case syscall.ARPHRD_ATM:
126
+	case unix.ARPHRD_ATM:
127 127
 		return "atm"
128
-	case syscall.ARPHRD_METRICOM:
128
+	case unix.ARPHRD_METRICOM:
129 129
 		return "metricom"
130
-	case syscall.ARPHRD_IEEE1394:
130
+	case unix.ARPHRD_IEEE1394:
131 131
 		return "ieee1394"
132
-	case syscall.ARPHRD_INFINIBAND:
132
+	case unix.ARPHRD_INFINIBAND:
133 133
 		return "infiniband"
134
-	case syscall.ARPHRD_SLIP:
134
+	case unix.ARPHRD_SLIP:
135 135
 		return "slip"
136
-	case syscall.ARPHRD_CSLIP:
136
+	case unix.ARPHRD_CSLIP:
137 137
 		return "cslip"
138
-	case syscall.ARPHRD_SLIP6:
138
+	case unix.ARPHRD_SLIP6:
139 139
 		return "slip6"
140
-	case syscall.ARPHRD_CSLIP6:
140
+	case unix.ARPHRD_CSLIP6:
141 141
 		return "cslip6"
142
-	case syscall.ARPHRD_RSRVD:
142
+	case unix.ARPHRD_RSRVD:
143 143
 		return "rsrvd"
144
-	case syscall.ARPHRD_ADAPT:
144
+	case unix.ARPHRD_ADAPT:
145 145
 		return "adapt"
146
-	case syscall.ARPHRD_ROSE:
146
+	case unix.ARPHRD_ROSE:
147 147
 		return "rose"
148
-	case syscall.ARPHRD_X25:
148
+	case unix.ARPHRD_X25:
149 149
 		return "x25"
150
-	case syscall.ARPHRD_HWX25:
150
+	case unix.ARPHRD_HWX25:
151 151
 		return "hwx25"
152
-	case syscall.ARPHRD_PPP:
152
+	case unix.ARPHRD_PPP:
153 153
 		return "ppp"
154
-	case syscall.ARPHRD_HDLC:
154
+	case unix.ARPHRD_HDLC:
155 155
 		return "hdlc"
156
-	case syscall.ARPHRD_LAPB:
156
+	case unix.ARPHRD_LAPB:
157 157
 		return "lapb"
158
-	case syscall.ARPHRD_DDCMP:
158
+	case unix.ARPHRD_DDCMP:
159 159
 		return "ddcmp"
160
-	case syscall.ARPHRD_RAWHDLC:
160
+	case unix.ARPHRD_RAWHDLC:
161 161
 		return "rawhdlc"
162
-	case syscall.ARPHRD_TUNNEL:
162
+	case unix.ARPHRD_TUNNEL:
163 163
 		return "ipip"
164
-	case syscall.ARPHRD_TUNNEL6:
164
+	case unix.ARPHRD_TUNNEL6:
165 165
 		return "tunnel6"
166
-	case syscall.ARPHRD_FRAD:
166
+	case unix.ARPHRD_FRAD:
167 167
 		return "frad"
168
-	case syscall.ARPHRD_SKIP:
168
+	case unix.ARPHRD_SKIP:
169 169
 		return "skip"
170
-	case syscall.ARPHRD_LOOPBACK:
170
+	case unix.ARPHRD_LOOPBACK:
171 171
 		return "loopback"
172
-	case syscall.ARPHRD_LOCALTLK:
172
+	case unix.ARPHRD_LOCALTLK:
173 173
 		return "ltalk"
174
-	case syscall.ARPHRD_FDDI:
174
+	case unix.ARPHRD_FDDI:
175 175
 		return "fddi"
176
-	case syscall.ARPHRD_BIF:
176
+	case unix.ARPHRD_BIF:
177 177
 		return "bif"
178
-	case syscall.ARPHRD_SIT:
178
+	case unix.ARPHRD_SIT:
179 179
 		return "sit"
180
-	case syscall.ARPHRD_IPDDP:
180
+	case unix.ARPHRD_IPDDP:
181 181
 		return "ip/ddp"
182
-	case syscall.ARPHRD_IPGRE:
182
+	case unix.ARPHRD_IPGRE:
183 183
 		return "gre"
184
-	case syscall.ARPHRD_PIMREG:
184
+	case unix.ARPHRD_PIMREG:
185 185
 		return "pimreg"
186
-	case syscall.ARPHRD_HIPPI:
186
+	case unix.ARPHRD_HIPPI:
187 187
 		return "hippi"
188
-	case syscall.ARPHRD_ASH:
188
+	case unix.ARPHRD_ASH:
189 189
 		return "ash"
190
-	case syscall.ARPHRD_ECONET:
190
+	case unix.ARPHRD_ECONET:
191 191
 		return "econet"
192
-	case syscall.ARPHRD_IRDA:
192
+	case unix.ARPHRD_IRDA:
193 193
 		return "irda"
194
-	case syscall.ARPHRD_FCPP:
194
+	case unix.ARPHRD_FCPP:
195 195
 		return "fcpp"
196
-	case syscall.ARPHRD_FCAL:
196
+	case unix.ARPHRD_FCAL:
197 197
 		return "fcal"
198
-	case syscall.ARPHRD_FCPL:
198
+	case unix.ARPHRD_FCPL:
199 199
 		return "fcpl"
200
-	case syscall.ARPHRD_FCFABRIC:
200
+	case unix.ARPHRD_FCFABRIC:
201 201
 		return "fcfb0"
202
-	case syscall.ARPHRD_FCFABRIC + 1:
202
+	case unix.ARPHRD_FCFABRIC + 1:
203 203
 		return "fcfb1"
204
-	case syscall.ARPHRD_FCFABRIC + 2:
204
+	case unix.ARPHRD_FCFABRIC + 2:
205 205
 		return "fcfb2"
206
-	case syscall.ARPHRD_FCFABRIC + 3:
206
+	case unix.ARPHRD_FCFABRIC + 3:
207 207
 		return "fcfb3"
208
-	case syscall.ARPHRD_FCFABRIC + 4:
208
+	case unix.ARPHRD_FCFABRIC + 4:
209 209
 		return "fcfb4"
210
-	case syscall.ARPHRD_FCFABRIC + 5:
210
+	case unix.ARPHRD_FCFABRIC + 5:
211 211
 		return "fcfb5"
212
-	case syscall.ARPHRD_FCFABRIC + 6:
212
+	case unix.ARPHRD_FCFABRIC + 6:
213 213
 		return "fcfb6"
214
-	case syscall.ARPHRD_FCFABRIC + 7:
214
+	case unix.ARPHRD_FCFABRIC + 7:
215 215
 		return "fcfb7"
216
-	case syscall.ARPHRD_FCFABRIC + 8:
216
+	case unix.ARPHRD_FCFABRIC + 8:
217 217
 		return "fcfb8"
218
-	case syscall.ARPHRD_FCFABRIC + 9:
218
+	case unix.ARPHRD_FCFABRIC + 9:
219 219
 		return "fcfb9"
220
-	case syscall.ARPHRD_FCFABRIC + 10:
220
+	case unix.ARPHRD_FCFABRIC + 10:
221 221
 		return "fcfb10"
222
-	case syscall.ARPHRD_FCFABRIC + 11:
222
+	case unix.ARPHRD_FCFABRIC + 11:
223 223
 		return "fcfb11"
224
-	case syscall.ARPHRD_FCFABRIC + 12:
224
+	case unix.ARPHRD_FCFABRIC + 12:
225 225
 		return "fcfb12"
226
-	case syscall.ARPHRD_IEEE802_TR:
226
+	case unix.ARPHRD_IEEE802_TR:
227 227
 		return "tr"
228
-	case syscall.ARPHRD_IEEE80211:
228
+	case unix.ARPHRD_IEEE80211:
229 229
 		return "ieee802.11"
230
-	case syscall.ARPHRD_IEEE80211_PRISM:
230
+	case unix.ARPHRD_IEEE80211_PRISM:
231 231
 		return "ieee802.11/prism"
232
-	case syscall.ARPHRD_IEEE80211_RADIOTAP:
232
+	case unix.ARPHRD_IEEE80211_RADIOTAP:
233 233
 		return "ieee802.11/radiotap"
234
-	case syscall.ARPHRD_IEEE802154:
234
+	case unix.ARPHRD_IEEE802154:
235 235
 		return "ieee802.15.4"
236 236
 
237 237
 	case 65534:
... ...
@@ -243,7 +244,7 @@ func (msg *IfInfomsg) EncapType() string {
243 243
 }
244 244
 
245 245
 func rtaAlignOf(attrlen int) int {
246
-	return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1)
246
+	return (attrlen + unix.RTA_ALIGNTO - 1) & ^(unix.RTA_ALIGNTO - 1)
247 247
 }
248 248
 
249 249
 func NewIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
... ...
@@ -254,7 +255,7 @@ func NewIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
254 254
 
255 255
 // Extend RtAttr to handle data and children
256 256
 type RtAttr struct {
257
-	syscall.RtAttr
257
+	unix.RtAttr
258 258
 	Data     []byte
259 259
 	children []NetlinkRequestData
260 260
 }
... ...
@@ -262,7 +263,7 @@ type RtAttr struct {
262 262
 // Create a new Extended RtAttr object
263 263
 func NewRtAttr(attrType int, data []byte) *RtAttr {
264 264
 	return &RtAttr{
265
-		RtAttr: syscall.RtAttr{
265
+		RtAttr: unix.RtAttr{
266 266
 			Type: uint16(attrType),
267 267
 		},
268 268
 		children: []NetlinkRequestData{},
... ...
@@ -277,16 +278,21 @@ func NewRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr {
277 277
 	return attr
278 278
 }
279 279
 
280
+// AddChild adds an existing RtAttr as a child.
281
+func (a *RtAttr) AddChild(attr *RtAttr) {
282
+	a.children = append(a.children, attr)
283
+}
284
+
280 285
 func (a *RtAttr) Len() int {
281 286
 	if len(a.children) == 0 {
282
-		return (syscall.SizeofRtAttr + len(a.Data))
287
+		return (unix.SizeofRtAttr + len(a.Data))
283 288
 	}
284 289
 
285 290
 	l := 0
286 291
 	for _, child := range a.children {
287 292
 		l += rtaAlignOf(child.Len())
288 293
 	}
289
-	l += syscall.SizeofRtAttr
294
+	l += unix.SizeofRtAttr
290 295
 	return rtaAlignOf(l + len(a.Data))
291 296
 }
292 297
 
... ...
@@ -319,7 +325,7 @@ func (a *RtAttr) Serialize() []byte {
319 319
 }
320 320
 
321 321
 type NetlinkRequest struct {
322
-	syscall.NlMsghdr
322
+	unix.NlMsghdr
323 323
 	Data    []NetlinkRequestData
324 324
 	RawData []byte
325 325
 	Sockets map[int]*SocketHandle
... ...
@@ -327,7 +333,7 @@ type NetlinkRequest struct {
327 327
 
328 328
 // Serialize the Netlink Request into a byte array
329 329
 func (req *NetlinkRequest) Serialize() []byte {
330
-	length := syscall.SizeofNlMsghdr
330
+	length := unix.SizeofNlMsghdr
331 331
 	dataBytes := make([][]byte, len(req.Data))
332 332
 	for i, data := range req.Data {
333 333
 		dataBytes[i] = data.Serialize()
... ...
@@ -337,8 +343,8 @@ func (req *NetlinkRequest) Serialize() []byte {
337 337
 
338 338
 	req.Len = uint32(length)
339 339
 	b := make([]byte, length)
340
-	hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:]
341
-	next := syscall.SizeofNlMsghdr
340
+	hdr := (*(*[unix.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:]
341
+	next := unix.SizeofNlMsghdr
342 342
 	copy(b[0:next], hdr)
343 343
 	for _, data := range dataBytes {
344 344
 		for _, dataByte := range data {
... ...
@@ -421,10 +427,10 @@ done:
421 421
 			if m.Header.Pid != pid {
422 422
 				return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
423 423
 			}
424
-			if m.Header.Type == syscall.NLMSG_DONE {
424
+			if m.Header.Type == unix.NLMSG_DONE {
425 425
 				break done
426 426
 			}
427
-			if m.Header.Type == syscall.NLMSG_ERROR {
427
+			if m.Header.Type == unix.NLMSG_ERROR {
428 428
 				native := NativeEndian()
429 429
 				error := int32(native.Uint32(m.Data[0:4]))
430 430
 				if error == 0 {
... ...
@@ -436,7 +442,7 @@ done:
436 436
 				continue
437 437
 			}
438 438
 			res = append(res, m.Data)
439
-			if m.Header.Flags&syscall.NLM_F_MULTI == 0 {
439
+			if m.Header.Flags&unix.NLM_F_MULTI == 0 {
440 440
 				break done
441 441
 			}
442 442
 		}
... ...
@@ -449,10 +455,10 @@ done:
449 449
 // the message is serialized
450 450
 func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
451 451
 	return &NetlinkRequest{
452
-		NlMsghdr: syscall.NlMsghdr{
453
-			Len:   uint32(syscall.SizeofNlMsghdr),
452
+		NlMsghdr: unix.NlMsghdr{
453
+			Len:   uint32(unix.SizeofNlMsghdr),
454 454
 			Type:  uint16(proto),
455
-			Flags: syscall.NLM_F_REQUEST | uint16(flags),
455
+			Flags: unix.NLM_F_REQUEST | uint16(flags),
456 456
 			Seq:   atomic.AddUint32(&nextSeqNr, 1),
457 457
 		},
458 458
 	}
... ...
@@ -460,21 +466,21 @@ func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
460 460
 
461 461
 type NetlinkSocket struct {
462 462
 	fd  int32
463
-	lsa syscall.SockaddrNetlink
463
+	lsa unix.SockaddrNetlink
464 464
 	sync.Mutex
465 465
 }
466 466
 
467 467
 func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
468
-	fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW|syscall.SOCK_CLOEXEC, protocol)
468
+	fd, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_RAW|unix.SOCK_CLOEXEC, protocol)
469 469
 	if err != nil {
470 470
 		return nil, err
471 471
 	}
472 472
 	s := &NetlinkSocket{
473 473
 		fd: int32(fd),
474 474
 	}
475
-	s.lsa.Family = syscall.AF_NETLINK
476
-	if err := syscall.Bind(fd, &s.lsa); err != nil {
477
-		syscall.Close(fd)
475
+	s.lsa.Family = unix.AF_NETLINK
476
+	if err := unix.Bind(fd, &s.lsa); err != nil {
477
+		unix.Close(fd)
478 478
 		return nil, err
479 479
 	}
480 480
 
... ...
@@ -551,21 +557,21 @@ func executeInNetns(newNs, curNs netns.NsHandle) (func(), error) {
551 551
 // Returns the netlink socket on which Receive() method can be called
552 552
 // to retrieve the messages from the kernel.
553 553
 func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
554
-	fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol)
554
+	fd, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_RAW, protocol)
555 555
 	if err != nil {
556 556
 		return nil, err
557 557
 	}
558 558
 	s := &NetlinkSocket{
559 559
 		fd: int32(fd),
560 560
 	}
561
-	s.lsa.Family = syscall.AF_NETLINK
561
+	s.lsa.Family = unix.AF_NETLINK
562 562
 
563 563
 	for _, g := range groups {
564 564
 		s.lsa.Groups |= (1 << (g - 1))
565 565
 	}
566 566
 
567
-	if err := syscall.Bind(fd, &s.lsa); err != nil {
568
-		syscall.Close(fd)
567
+	if err := unix.Bind(fd, &s.lsa); err != nil {
568
+		unix.Close(fd)
569 569
 		return nil, err
570 570
 	}
571 571
 
... ...
@@ -586,7 +592,7 @@ func SubscribeAt(newNs, curNs netns.NsHandle, protocol int, groups ...uint) (*Ne
586 586
 
587 587
 func (s *NetlinkSocket) Close() {
588 588
 	fd := int(atomic.SwapInt32(&s.fd, -1))
589
-	syscall.Close(fd)
589
+	unix.Close(fd)
590 590
 }
591 591
 
592 592
 func (s *NetlinkSocket) GetFd() int {
... ...
@@ -598,7 +604,7 @@ func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
598 598
 	if fd < 0 {
599 599
 		return fmt.Errorf("Send called on a closed socket")
600 600
 	}
601
-	if err := syscall.Sendto(fd, request.Serialize(), 0, &s.lsa); err != nil {
601
+	if err := unix.Sendto(fd, request.Serialize(), 0, &s.lsa); err != nil {
602 602
 		return err
603 603
 	}
604 604
 	return nil
... ...
@@ -609,12 +615,12 @@ func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
609 609
 	if fd < 0 {
610 610
 		return nil, fmt.Errorf("Receive called on a closed socket")
611 611
 	}
612
-	rb := make([]byte, syscall.Getpagesize())
613
-	nr, _, err := syscall.Recvfrom(fd, rb, 0)
612
+	rb := make([]byte, unix.Getpagesize())
613
+	nr, _, err := unix.Recvfrom(fd, rb, 0)
614 614
 	if err != nil {
615 615
 		return nil, err
616 616
 	}
617
-	if nr < syscall.NLMSG_HDRLEN {
617
+	if nr < unix.NLMSG_HDRLEN {
618 618
 		return nil, fmt.Errorf("Got short response from netlink")
619 619
 	}
620 620
 	rb = rb[:nr]
... ...
@@ -622,27 +628,27 @@ func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
622 622
 }
623 623
 
624 624
 // SetSendTimeout allows to set a send timeout on the socket
625
-func (s *NetlinkSocket) SetSendTimeout(timeout *syscall.Timeval) error {
625
+func (s *NetlinkSocket) SetSendTimeout(timeout *unix.Timeval) error {
626 626
 	// Set a send timeout of SOCKET_SEND_TIMEOUT, this will allow the Send to periodically unblock and avoid that a routine
627 627
 	// remains stuck on a send on a closed fd
628
-	return syscall.SetsockoptTimeval(int(s.fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, timeout)
628
+	return unix.SetsockoptTimeval(int(s.fd), unix.SOL_SOCKET, unix.SO_SNDTIMEO, timeout)
629 629
 }
630 630
 
631 631
 // SetReceiveTimeout allows to set a receive timeout on the socket
632
-func (s *NetlinkSocket) SetReceiveTimeout(timeout *syscall.Timeval) error {
632
+func (s *NetlinkSocket) SetReceiveTimeout(timeout *unix.Timeval) error {
633 633
 	// Set a read timeout of SOCKET_READ_TIMEOUT, this will allow the Read to periodically unblock and avoid that a routine
634 634
 	// remains stuck on a recvmsg on a closed fd
635
-	return syscall.SetsockoptTimeval(int(s.fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, timeout)
635
+	return unix.SetsockoptTimeval(int(s.fd), unix.SOL_SOCKET, unix.SO_RCVTIMEO, timeout)
636 636
 }
637 637
 
638 638
 func (s *NetlinkSocket) GetPid() (uint32, error) {
639 639
 	fd := int(atomic.LoadInt32(&s.fd))
640
-	lsa, err := syscall.Getsockname(fd)
640
+	lsa, err := unix.Getsockname(fd)
641 641
 	if err != nil {
642 642
 		return 0, err
643 643
 	}
644 644
 	switch v := lsa.(type) {
645
-	case *syscall.SockaddrNetlink:
645
+	case *unix.SockaddrNetlink:
646 646
 		return v.Pid, nil
647 647
 	}
648 648
 	return 0, fmt.Errorf("Wrong socket type")
... ...
@@ -697,24 +703,24 @@ func Uint64Attr(v uint64) []byte {
697 697
 
698 698
 func ParseRouteAttr(b []byte) ([]syscall.NetlinkRouteAttr, error) {
699 699
 	var attrs []syscall.NetlinkRouteAttr
700
-	for len(b) >= syscall.SizeofRtAttr {
700
+	for len(b) >= unix.SizeofRtAttr {
701 701
 		a, vbuf, alen, err := netlinkRouteAttrAndValue(b)
702 702
 		if err != nil {
703 703
 			return nil, err
704 704
 		}
705
-		ra := syscall.NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-syscall.SizeofRtAttr]}
705
+		ra := syscall.NetlinkRouteAttr{Attr: syscall.RtAttr(*a), Value: vbuf[:int(a.Len)-unix.SizeofRtAttr]}
706 706
 		attrs = append(attrs, ra)
707 707
 		b = b[alen:]
708 708
 	}
709 709
 	return attrs, nil
710 710
 }
711 711
 
712
-func netlinkRouteAttrAndValue(b []byte) (*syscall.RtAttr, []byte, int, error) {
713
-	a := (*syscall.RtAttr)(unsafe.Pointer(&b[0]))
714
-	if int(a.Len) < syscall.SizeofRtAttr || int(a.Len) > len(b) {
715
-		return nil, nil, 0, syscall.EINVAL
712
+func netlinkRouteAttrAndValue(b []byte) (*unix.RtAttr, []byte, int, error) {
713
+	a := (*unix.RtAttr)(unsafe.Pointer(&b[0]))
714
+	if int(a.Len) < unix.SizeofRtAttr || int(a.Len) > len(b) {
715
+		return nil, nil, 0, unix.EINVAL
716 716
 	}
717
-	return a, b[syscall.SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil
717
+	return a, b[unix.SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil
718 718
 }
719 719
 
720 720
 // SocketHandle contains the netlink socket and the associated
... ...
@@ -1,65 +1,66 @@
1 1
 package nl
2 2
 
3 3
 import (
4
-	"syscall"
5 4
 	"unsafe"
5
+
6
+	"golang.org/x/sys/unix"
6 7
 )
7 8
 
8 9
 type RtMsg struct {
9
-	syscall.RtMsg
10
+	unix.RtMsg
10 11
 }
11 12
 
12 13
 func NewRtMsg() *RtMsg {
13 14
 	return &RtMsg{
14
-		RtMsg: syscall.RtMsg{
15
-			Table:    syscall.RT_TABLE_MAIN,
16
-			Scope:    syscall.RT_SCOPE_UNIVERSE,
17
-			Protocol: syscall.RTPROT_BOOT,
18
-			Type:     syscall.RTN_UNICAST,
15
+		RtMsg: unix.RtMsg{
16
+			Table:    unix.RT_TABLE_MAIN,
17
+			Scope:    unix.RT_SCOPE_UNIVERSE,
18
+			Protocol: unix.RTPROT_BOOT,
19
+			Type:     unix.RTN_UNICAST,
19 20
 		},
20 21
 	}
21 22
 }
22 23
 
23 24
 func NewRtDelMsg() *RtMsg {
24 25
 	return &RtMsg{
25
-		RtMsg: syscall.RtMsg{
26
-			Table: syscall.RT_TABLE_MAIN,
27
-			Scope: syscall.RT_SCOPE_NOWHERE,
26
+		RtMsg: unix.RtMsg{
27
+			Table: unix.RT_TABLE_MAIN,
28
+			Scope: unix.RT_SCOPE_NOWHERE,
28 29
 		},
29 30
 	}
30 31
 }
31 32
 
32 33
 func (msg *RtMsg) Len() int {
33
-	return syscall.SizeofRtMsg
34
+	return unix.SizeofRtMsg
34 35
 }
35 36
 
36 37
 func DeserializeRtMsg(b []byte) *RtMsg {
37
-	return (*RtMsg)(unsafe.Pointer(&b[0:syscall.SizeofRtMsg][0]))
38
+	return (*RtMsg)(unsafe.Pointer(&b[0:unix.SizeofRtMsg][0]))
38 39
 }
39 40
 
40 41
 func (msg *RtMsg) Serialize() []byte {
41
-	return (*(*[syscall.SizeofRtMsg]byte)(unsafe.Pointer(msg)))[:]
42
+	return (*(*[unix.SizeofRtMsg]byte)(unsafe.Pointer(msg)))[:]
42 43
 }
43 44
 
44 45
 type RtNexthop struct {
45
-	syscall.RtNexthop
46
+	unix.RtNexthop
46 47
 	Children []NetlinkRequestData
47 48
 }
48 49
 
49 50
 func DeserializeRtNexthop(b []byte) *RtNexthop {
50
-	return (*RtNexthop)(unsafe.Pointer(&b[0:syscall.SizeofRtNexthop][0]))
51
+	return (*RtNexthop)(unsafe.Pointer(&b[0:unix.SizeofRtNexthop][0]))
51 52
 }
52 53
 
53 54
 func (msg *RtNexthop) Len() int {
54 55
 	if len(msg.Children) == 0 {
55
-		return syscall.SizeofRtNexthop
56
+		return unix.SizeofRtNexthop
56 57
 	}
57 58
 
58 59
 	l := 0
59 60
 	for _, child := range msg.Children {
60 61
 		l += rtaAlignOf(child.Len())
61 62
 	}
62
-	l += syscall.SizeofRtNexthop
63
+	l += unix.SizeofRtNexthop
63 64
 	return rtaAlignOf(l)
64 65
 }
65 66
 
... ...
@@ -67,8 +68,8 @@ func (msg *RtNexthop) Serialize() []byte {
67 67
 	length := msg.Len()
68 68
 	msg.RtNexthop.Len = uint16(length)
69 69
 	buf := make([]byte, length)
70
-	copy(buf, (*(*[syscall.SizeofRtNexthop]byte)(unsafe.Pointer(msg)))[:])
71
-	next := rtaAlignOf(syscall.SizeofRtNexthop)
70
+	copy(buf, (*(*[unix.SizeofRtNexthop]byte)(unsafe.Pointer(msg)))[:])
71
+	next := rtaAlignOf(unix.SizeofRtNexthop)
72 72
 	if len(msg.Children) > 0 {
73 73
 		for _, child := range msg.Children {
74 74
 			childBuf := child.Serialize()
75 75
new file mode 100644
... ...
@@ -0,0 +1,111 @@
0
+package nl
1
+
2
+import (
3
+	"errors"
4
+	"fmt"
5
+	"net"
6
+)
7
+
8
+type IPv6SrHdr struct {
9
+	nextHdr      uint8
10
+	hdrLen       uint8
11
+	routingType  uint8
12
+	segmentsLeft uint8
13
+	firstSegment uint8
14
+	flags        uint8
15
+	reserved     uint16
16
+
17
+	Segments []net.IP
18
+}
19
+
20
+func (s1 *IPv6SrHdr) Equal(s2 IPv6SrHdr) bool {
21
+	if len(s1.Segments) != len(s2.Segments) {
22
+		return false
23
+	}
24
+	for i := range s1.Segments {
25
+		if s1.Segments[i].Equal(s2.Segments[i]) != true {
26
+			return false
27
+		}
28
+	}
29
+	return s1.nextHdr == s2.nextHdr &&
30
+		s1.hdrLen == s2.hdrLen &&
31
+		s1.routingType == s2.routingType &&
32
+		s1.segmentsLeft == s2.segmentsLeft &&
33
+		s1.firstSegment == s2.firstSegment &&
34
+		s1.flags == s2.flags
35
+	// reserved doesn't need to be identical.
36
+}
37
+
38
+// seg6 encap mode
39
+const (
40
+	SEG6_IPTUN_MODE_INLINE = iota
41
+	SEG6_IPTUN_MODE_ENCAP
42
+)
43
+
44
+// number of nested RTATTR
45
+// from include/uapi/linux/seg6_iptunnel.h
46
+const (
47
+	SEG6_IPTUNNEL_UNSPEC = iota
48
+	SEG6_IPTUNNEL_SRH
49
+	__SEG6_IPTUNNEL_MAX
50
+)
51
+const (
52
+	SEG6_IPTUNNEL_MAX = __SEG6_IPTUNNEL_MAX - 1
53
+)
54
+
55
+func EncodeSEG6Encap(mode int, segments []net.IP) ([]byte, error) {
56
+	nsegs := len(segments) // nsegs: number of segments
57
+	if nsegs == 0 {
58
+		return nil, errors.New("EncodeSEG6Encap: No Segment in srh")
59
+	}
60
+	b := make([]byte, 12, 12+len(segments)*16)
61
+	native := NativeEndian()
62
+	native.PutUint32(b, uint32(mode))
63
+	b[4] = 0                      // srh.nextHdr (0 when calling netlink)
64
+	b[5] = uint8(16 * nsegs >> 3) // srh.hdrLen (in 8-octets unit)
65
+	b[6] = IPV6_SRCRT_TYPE_4      // srh.routingType (assigned by IANA)
66
+	b[7] = uint8(nsegs - 1)       // srh.segmentsLeft
67
+	b[8] = uint8(nsegs - 1)       // srh.firstSegment
68
+	b[9] = 0                      // srh.flags (SR6_FLAG1_HMAC for srh_hmac)
69
+	// srh.reserved: Defined as "Tag" in draft-ietf-6man-segment-routing-header-07
70
+	native.PutUint16(b[10:], 0) // srh.reserved
71
+	for _, netIP := range segments {
72
+		b = append(b, netIP...) // srh.Segments
73
+	}
74
+	return b, nil
75
+}
76
+
77
+func DecodeSEG6Encap(buf []byte) (int, []net.IP, error) {
78
+	native := NativeEndian()
79
+	mode := int(native.Uint32(buf))
80
+	srh := IPv6SrHdr{
81
+		nextHdr:      buf[4],
82
+		hdrLen:       buf[5],
83
+		routingType:  buf[6],
84
+		segmentsLeft: buf[7],
85
+		firstSegment: buf[8],
86
+		flags:        buf[9],
87
+		reserved:     native.Uint16(buf[10:12]),
88
+	}
89
+	buf = buf[12:]
90
+	if len(buf)%16 != 0 {
91
+		err := fmt.Errorf("DecodeSEG6Encap: error parsing Segment List (buf len: %d)\n", len(buf))
92
+		return mode, nil, err
93
+	}
94
+	for len(buf) > 0 {
95
+		srh.Segments = append(srh.Segments, net.IP(buf[:16]))
96
+		buf = buf[16:]
97
+	}
98
+	return mode, srh.Segments, nil
99
+}
100
+
101
+// Helper functions
102
+func SEG6EncapModeString(mode int) string {
103
+	switch mode {
104
+	case SEG6_IPTUN_MODE_INLINE:
105
+		return "inline"
106
+	case SEG6_IPTUN_MODE_ENCAP:
107
+		return "encap"
108
+	}
109
+	return "unknown"
110
+}
... ...
@@ -65,4 +65,14 @@ const (
65 65
 	LWTUNNEL_ENCAP_IP
66 66
 	LWTUNNEL_ENCAP_ILA
67 67
 	LWTUNNEL_ENCAP_IP6
68
+	LWTUNNEL_ENCAP_SEG6
69
+	LWTUNNEL_ENCAP_BPF
70
+)
71
+
72
+// routing header types
73
+const (
74
+	IPV6_SRCRT_STRICT = 0x01 // Deprecated; will be removed
75
+	IPV6_SRCRT_TYPE_0 = 0    // Deprecated; will be removed
76
+	IPV6_SRCRT_TYPE_2 = 2    // IPv6 type 2 Routing Header
77
+	IPV6_SRCRT_TYPE_4 = 4    // Segment Routing with IPv6
68 78
 )
... ...
@@ -673,3 +673,38 @@ const (
673 673
 	TCA_FW_MASK
674 674
 	TCA_FW_MAX = TCA_FW_MASK
675 675
 )
676
+
677
+const (
678
+	TCA_MATCHALL_UNSPEC = iota
679
+	TCA_MATCHALL_CLASSID
680
+	TCA_MATCHALL_ACT
681
+	TCA_MATCHALL_FLAGS
682
+)
683
+
684
+const (
685
+	TCA_FQ_UNSPEC             = iota
686
+	TCA_FQ_PLIMIT             // limit of total number of packets in queue
687
+	TCA_FQ_FLOW_PLIMIT        // limit of packets per flow
688
+	TCA_FQ_QUANTUM            // RR quantum
689
+	TCA_FQ_INITIAL_QUANTUM    // RR quantum for new flow
690
+	TCA_FQ_RATE_ENABLE        // enable/disable rate limiting
691
+	TCA_FQ_FLOW_DEFAULT_RATE  // obsolete do not use
692
+	TCA_FQ_FLOW_MAX_RATE      // per flow max rate
693
+	TCA_FQ_BUCKETS_LOG        // log2(number of buckets)
694
+	TCA_FQ_FLOW_REFILL_DELAY  // flow credit refill delay in usec
695
+	TCA_FQ_ORPHAN_MASK        // mask applied to orphaned skb hashes
696
+	TCA_FQ_LOW_RATE_THRESHOLD // per packet delay under this rate
697
+)
698
+
699
+const (
700
+	TCA_FQ_CODEL_UNSPEC = iota
701
+	TCA_FQ_CODEL_TARGET
702
+	TCA_FQ_CODEL_LIMIT
703
+	TCA_FQ_CODEL_INTERVAL
704
+	TCA_FQ_CODEL_ECN
705
+	TCA_FQ_CODEL_FLOWS
706
+	TCA_FQ_CODEL_QUANTUM
707
+	TCA_FQ_CODEL_CE_THRESHOLD
708
+	TCA_FQ_CODEL_DROP_BATCH_SIZE
709
+	TCA_FQ_CODEL_MEMORY_LIMIT
710
+)
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"syscall"
6 6
 
7 7
 	"github.com/vishvananda/netlink/nl"
8
+	"golang.org/x/sys/unix"
8 9
 )
9 10
 
10 11
 func LinkGetProtinfo(link Link) (Protinfo, error) {
... ...
@@ -15,10 +16,10 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
15 15
 	base := link.Attrs()
16 16
 	h.ensureIndex(base)
17 17
 	var pi Protinfo
18
-	req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP)
19
-	msg := nl.NewIfInfomsg(syscall.AF_BRIDGE)
18
+	req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
19
+	msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
20 20
 	req.AddData(msg)
21
-	msgs, err := req.Execute(syscall.NETLINK_ROUTE, 0)
21
+	msgs, err := req.Execute(unix.NETLINK_ROUTE, 0)
22 22
 	if err != nil {
23 23
 		return pi, err
24 24
 	}
... ...
@@ -33,7 +34,7 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
33 33
 			return pi, err
34 34
 		}
35 35
 		for _, attr := range attrs {
36
-			if attr.Attr.Type != syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED {
36
+			if attr.Attr.Type != unix.IFLA_PROTINFO|unix.NLA_F_NESTED {
37 37
 				continue
38 38
 			}
39 39
 			infos, err := nl.ParseRouteAttr(attr.Value)
... ...
@@ -230,3 +230,63 @@ func (qdisc *GenericQdisc) Attrs() *QdiscAttrs {
230 230
 func (qdisc *GenericQdisc) Type() string {
231 231
 	return qdisc.QdiscType
232 232
 }
233
+
234
+// Fq is a classless packet scheduler meant to be mostly used for locally generated traffic.
235
+type Fq struct {
236
+	QdiscAttrs
237
+	PacketLimit     uint32
238
+	FlowPacketLimit uint32
239
+	// In bytes
240
+	Quantum        uint32
241
+	InitialQuantum uint32
242
+	// called RateEnable under the hood
243
+	Pacing          uint32
244
+	FlowDefaultRate uint32
245
+	FlowMaxRate     uint32
246
+	// called BucketsLog under the hood
247
+	Buckets          uint32
248
+	FlowRefillDelay  uint32
249
+	LowRateThreshold uint32
250
+}
251
+
252
+func NewFq(attrs QdiscAttrs) *Fq {
253
+	return &Fq{
254
+		QdiscAttrs: attrs,
255
+		Pacing:     1,
256
+	}
257
+}
258
+
259
+func (qdisc *Fq) Attrs() *QdiscAttrs {
260
+	return &qdisc.QdiscAttrs
261
+}
262
+
263
+func (qdisc *Fq) Type() string {
264
+	return "fq"
265
+}
266
+
267
+// FQ_Codel (Fair Queuing Controlled Delay) is queuing discipline that combines Fair Queuing with the CoDel AQM scheme.
268
+type FqCodel struct {
269
+	QdiscAttrs
270
+	Target   uint32
271
+	Limit    uint32
272
+	Interval uint32
273
+	ECN      uint32
274
+	Flows    uint32
275
+	Quantum  uint32
276
+	// There are some more attributes here, but support for them seems not ubiquitous
277
+}
278
+
279
+func NewFqCodel(attrs QdiscAttrs) *FqCodel {
280
+	return &FqCodel{
281
+		QdiscAttrs: attrs,
282
+		ECN:        1,
283
+	}
284
+}
285
+
286
+func (qdisc *FqCodel) Attrs() *QdiscAttrs {
287
+	return &qdisc.QdiscAttrs
288
+}
289
+
290
+func (qdisc *FqCodel) Type() string {
291
+	return "fq_codel"
292
+}
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"syscall"
9 9
 
10 10
 	"github.com/vishvananda/netlink/nl"
11
+	"golang.org/x/sys/unix"
11 12
 )
12 13
 
13 14
 // NOTE function is here because it uses other linux functions
... ...
@@ -84,7 +85,7 @@ func QdiscDel(qdisc Qdisc) error {
84 84
 // QdiscDel will delete a qdisc from the system.
85 85
 // Equivalent to: `tc qdisc del $qdisc`
86 86
 func (h *Handle) QdiscDel(qdisc Qdisc) error {
87
-	return h.qdiscModify(syscall.RTM_DELQDISC, 0, qdisc)
87
+	return h.qdiscModify(unix.RTM_DELQDISC, 0, qdisc)
88 88
 }
89 89
 
90 90
 // QdiscChange will change a qdisc in place
... ...
@@ -98,7 +99,7 @@ func QdiscChange(qdisc Qdisc) error {
98 98
 // Equivalent to: `tc qdisc change $qdisc`
99 99
 // The parent and handle MUST NOT be changed.
100 100
 func (h *Handle) QdiscChange(qdisc Qdisc) error {
101
-	return h.qdiscModify(syscall.RTM_NEWQDISC, 0, qdisc)
101
+	return h.qdiscModify(unix.RTM_NEWQDISC, 0, qdisc)
102 102
 }
103 103
 
104 104
 // QdiscReplace will replace a qdisc to the system.
... ...
@@ -113,8 +114,8 @@ func QdiscReplace(qdisc Qdisc) error {
113 113
 // The handle MUST change.
114 114
 func (h *Handle) QdiscReplace(qdisc Qdisc) error {
115 115
 	return h.qdiscModify(
116
-		syscall.RTM_NEWQDISC,
117
-		syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE,
116
+		unix.RTM_NEWQDISC,
117
+		unix.NLM_F_CREATE|unix.NLM_F_REPLACE,
118 118
 		qdisc)
119 119
 }
120 120
 
... ...
@@ -128,13 +129,13 @@ func QdiscAdd(qdisc Qdisc) error {
128 128
 // Equivalent to: `tc qdisc add $qdisc`
129 129
 func (h *Handle) QdiscAdd(qdisc Qdisc) error {
130 130
 	return h.qdiscModify(
131
-		syscall.RTM_NEWQDISC,
132
-		syscall.NLM_F_CREATE|syscall.NLM_F_EXCL,
131
+		unix.RTM_NEWQDISC,
132
+		unix.NLM_F_CREATE|unix.NLM_F_EXCL,
133 133
 		qdisc)
134 134
 }
135 135
 
136 136
 func (h *Handle) qdiscModify(cmd, flags int, qdisc Qdisc) error {
137
-	req := h.newNetlinkRequest(cmd, flags|syscall.NLM_F_ACK)
137
+	req := h.newNetlinkRequest(cmd, flags|unix.NLM_F_ACK)
138 138
 	base := qdisc.Attrs()
139 139
 	msg := &nl.TcMsg{
140 140
 		Family:  nl.FAMILY_ALL,
... ...
@@ -145,13 +146,13 @@ func (h *Handle) qdiscModify(cmd, flags int, qdisc Qdisc) error {
145 145
 	req.AddData(msg)
146 146
 
147 147
 	// When deleting don't bother building the rest of the netlink payload
148
-	if cmd != syscall.RTM_DELQDISC {
148
+	if cmd != unix.RTM_DELQDISC {
149 149
 		if err := qdiscPayload(req, qdisc); err != nil {
150 150
 			return err
151 151
 		}
152 152
 	}
153 153
 
154
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
154
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
155 155
 	return err
156 156
 }
157 157
 
... ...
@@ -231,6 +232,48 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
231 231
 		if qdisc.Attrs().Parent != HANDLE_INGRESS {
232 232
 			return fmt.Errorf("Ingress filters must set Parent to HANDLE_INGRESS")
233 233
 		}
234
+	case *FqCodel:
235
+		nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_ECN, nl.Uint32Attr((uint32(qdisc.ECN))))
236
+		if qdisc.Limit > 0 {
237
+			nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_LIMIT, nl.Uint32Attr((uint32(qdisc.Limit))))
238
+		}
239
+		if qdisc.Interval > 0 {
240
+			nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_INTERVAL, nl.Uint32Attr((uint32(qdisc.Interval))))
241
+		}
242
+		if qdisc.Flows > 0 {
243
+			nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_FLOWS, nl.Uint32Attr((uint32(qdisc.Flows))))
244
+		}
245
+		if qdisc.Quantum > 0 {
246
+			nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
247
+		}
248
+
249
+	case *Fq:
250
+		nl.NewRtAttrChild(options, nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing))))
251
+
252
+		if qdisc.Buckets > 0 {
253
+			nl.NewRtAttrChild(options, nl.TCA_FQ_BUCKETS_LOG, nl.Uint32Attr((uint32(qdisc.Buckets))))
254
+		}
255
+		if qdisc.LowRateThreshold > 0 {
256
+			nl.NewRtAttrChild(options, nl.TCA_FQ_LOW_RATE_THRESHOLD, nl.Uint32Attr((uint32(qdisc.LowRateThreshold))))
257
+		}
258
+		if qdisc.Quantum > 0 {
259
+			nl.NewRtAttrChild(options, nl.TCA_FQ_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
260
+		}
261
+		if qdisc.InitialQuantum > 0 {
262
+			nl.NewRtAttrChild(options, nl.TCA_FQ_INITIAL_QUANTUM, nl.Uint32Attr((uint32(qdisc.InitialQuantum))))
263
+		}
264
+		if qdisc.FlowRefillDelay > 0 {
265
+			nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_REFILL_DELAY, nl.Uint32Attr((uint32(qdisc.FlowRefillDelay))))
266
+		}
267
+		if qdisc.FlowPacketLimit > 0 {
268
+			nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_PLIMIT, nl.Uint32Attr((uint32(qdisc.FlowPacketLimit))))
269
+		}
270
+		if qdisc.FlowMaxRate > 0 {
271
+			nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_MAX_RATE, nl.Uint32Attr((uint32(qdisc.FlowMaxRate))))
272
+		}
273
+		if qdisc.FlowDefaultRate > 0 {
274
+			nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_DEFAULT_RATE, nl.Uint32Attr((uint32(qdisc.FlowDefaultRate))))
275
+		}
234 276
 	}
235 277
 
236 278
 	req.AddData(options)
... ...
@@ -248,7 +291,7 @@ func QdiscList(link Link) ([]Qdisc, error) {
248 248
 // Equivalent to: `tc qdisc show`.
249 249
 // The list can be filtered by link.
250 250
 func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
251
-	req := h.newNetlinkRequest(syscall.RTM_GETQDISC, syscall.NLM_F_DUMP)
251
+	req := h.newNetlinkRequest(unix.RTM_GETQDISC, unix.NLM_F_DUMP)
252 252
 	index := int32(0)
253 253
 	if link != nil {
254 254
 		base := link.Attrs()
... ...
@@ -261,7 +304,7 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
261 261
 	}
262 262
 	req.AddData(msg)
263 263
 
264
-	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWQDISC)
264
+	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWQDISC)
265 265
 	if err != nil {
266 266
 		return nil, err
267 267
 	}
... ...
@@ -303,6 +346,10 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
303 303
 					qdisc = &Ingress{}
304 304
 				case "htb":
305 305
 					qdisc = &Htb{}
306
+				case "fq":
307
+					qdisc = &Fq{}
308
+				case "fq_codel":
309
+					qdisc = &FqCodel{}
306 310
 				case "netem":
307 311
 					qdisc = &Netem{}
308 312
 				default:
... ...
@@ -336,6 +383,22 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
336 336
 					if err := parseHtbData(qdisc, data); err != nil {
337 337
 						return nil, err
338 338
 					}
339
+				case "fq":
340
+					data, err := nl.ParseRouteAttr(attr.Value)
341
+					if err != nil {
342
+						return nil, err
343
+					}
344
+					if err := parseFqData(qdisc, data); err != nil {
345
+						return nil, err
346
+					}
347
+				case "fq_codel":
348
+					data, err := nl.ParseRouteAttr(attr.Value)
349
+					if err != nil {
350
+						return nil, err
351
+					}
352
+					if err := parseFqCodelData(qdisc, data); err != nil {
353
+						return nil, err
354
+					}
339 355
 				case "netem":
340 356
 					if err := parseNetemData(qdisc, attr.Value); err != nil {
341 357
 						return nil, err
... ...
@@ -388,6 +451,61 @@ func parseHtbData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
388 388
 	return nil
389 389
 }
390 390
 
391
+func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
392
+	native = nl.NativeEndian()
393
+	fqCodel := qdisc.(*FqCodel)
394
+	for _, datum := range data {
395
+
396
+		switch datum.Attr.Type {
397
+		case nl.TCA_FQ_CODEL_TARGET:
398
+			fqCodel.Target = native.Uint32(datum.Value)
399
+		case nl.TCA_FQ_CODEL_LIMIT:
400
+			fqCodel.Limit = native.Uint32(datum.Value)
401
+		case nl.TCA_FQ_CODEL_INTERVAL:
402
+			fqCodel.Interval = native.Uint32(datum.Value)
403
+		case nl.TCA_FQ_CODEL_ECN:
404
+			fqCodel.ECN = native.Uint32(datum.Value)
405
+		case nl.TCA_FQ_CODEL_FLOWS:
406
+			fqCodel.Flows = native.Uint32(datum.Value)
407
+		case nl.TCA_FQ_CODEL_QUANTUM:
408
+			fqCodel.Quantum = native.Uint32(datum.Value)
409
+		}
410
+	}
411
+	return nil
412
+}
413
+
414
+func parseFqData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
415
+	native = nl.NativeEndian()
416
+	fq := qdisc.(*Fq)
417
+	for _, datum := range data {
418
+		switch datum.Attr.Type {
419
+		case nl.TCA_FQ_BUCKETS_LOG:
420
+			fq.Buckets = native.Uint32(datum.Value)
421
+		case nl.TCA_FQ_LOW_RATE_THRESHOLD:
422
+			fq.LowRateThreshold = native.Uint32(datum.Value)
423
+		case nl.TCA_FQ_QUANTUM:
424
+			fq.Quantum = native.Uint32(datum.Value)
425
+		case nl.TCA_FQ_RATE_ENABLE:
426
+			fq.Pacing = native.Uint32(datum.Value)
427
+		case nl.TCA_FQ_INITIAL_QUANTUM:
428
+			fq.InitialQuantum = native.Uint32(datum.Value)
429
+		case nl.TCA_FQ_ORPHAN_MASK:
430
+			// TODO
431
+		case nl.TCA_FQ_FLOW_REFILL_DELAY:
432
+			fq.FlowRefillDelay = native.Uint32(datum.Value)
433
+		case nl.TCA_FQ_FLOW_PLIMIT:
434
+			fq.FlowPacketLimit = native.Uint32(datum.Value)
435
+		case nl.TCA_FQ_PLIMIT:
436
+			fq.PacketLimit = native.Uint32(datum.Value)
437
+		case nl.TCA_FQ_FLOW_MAX_RATE:
438
+			fq.FlowMaxRate = native.Uint32(datum.Value)
439
+		case nl.TCA_FQ_FLOW_DEFAULT_RATE:
440
+			fq.FlowDefaultRate = native.Uint32(datum.Value)
441
+		}
442
+	}
443
+	return nil
444
+}
445
+
391 446
 func parseNetemData(qdisc Qdisc, value []byte) error {
392 447
 	netem := qdisc.(*Netem)
393 448
 	opt := nl.DeserializeTcNetemQopt(value)
... ...
@@ -45,6 +45,8 @@ type Route struct {
45 45
 	MPLSDst    *int
46 46
 	NewDst     Destination
47 47
 	Encap      Encap
48
+	MTU        int
49
+	AdvMSS     int
48 50
 }
49 51
 
50 52
 func (r Route) String() string {
... ...
@@ -8,16 +8,17 @@ import (
8 8
 
9 9
 	"github.com/vishvananda/netlink/nl"
10 10
 	"github.com/vishvananda/netns"
11
+	"golang.org/x/sys/unix"
11 12
 )
12 13
 
13 14
 // RtAttr is shared so it is in netlink_linux.go
14 15
 
15 16
 const (
16
-	SCOPE_UNIVERSE Scope = syscall.RT_SCOPE_UNIVERSE
17
-	SCOPE_SITE     Scope = syscall.RT_SCOPE_SITE
18
-	SCOPE_LINK     Scope = syscall.RT_SCOPE_LINK
19
-	SCOPE_HOST     Scope = syscall.RT_SCOPE_HOST
20
-	SCOPE_NOWHERE  Scope = syscall.RT_SCOPE_NOWHERE
17
+	SCOPE_UNIVERSE Scope = unix.RT_SCOPE_UNIVERSE
18
+	SCOPE_SITE     Scope = unix.RT_SCOPE_SITE
19
+	SCOPE_LINK     Scope = unix.RT_SCOPE_LINK
20
+	SCOPE_HOST     Scope = unix.RT_SCOPE_HOST
21
+	SCOPE_NOWHERE  Scope = unix.RT_SCOPE_NOWHERE
21 22
 )
22 23
 
23 24
 const (
... ...
@@ -34,8 +35,8 @@ const (
34 34
 )
35 35
 
36 36
 const (
37
-	FLAG_ONLINK    NextHopFlag = syscall.RTNH_F_ONLINK
38
-	FLAG_PERVASIVE NextHopFlag = syscall.RTNH_F_PERVASIVE
37
+	FLAG_ONLINK    NextHopFlag = unix.RTNH_F_ONLINK
38
+	FLAG_PERVASIVE NextHopFlag = unix.RTNH_F_PERVASIVE
39 39
 )
40 40
 
41 41
 var testFlags = []flagString{
... ...
@@ -124,17 +125,17 @@ func (e *MPLSEncap) Type() int {
124 124
 
125 125
 func (e *MPLSEncap) Decode(buf []byte) error {
126 126
 	if len(buf) < 4 {
127
-		return fmt.Errorf("Lack of bytes")
127
+		return fmt.Errorf("lack of bytes")
128 128
 	}
129 129
 	native := nl.NativeEndian()
130 130
 	l := native.Uint16(buf)
131 131
 	if len(buf) < int(l) {
132
-		return fmt.Errorf("Lack of bytes")
132
+		return fmt.Errorf("lack of bytes")
133 133
 	}
134 134
 	buf = buf[:l]
135 135
 	typ := native.Uint16(buf[2:])
136 136
 	if typ != nl.MPLS_IPTUNNEL_DST {
137
-		return fmt.Errorf("Unknown MPLS Encap Type: %d", typ)
137
+		return fmt.Errorf("unknown MPLS Encap Type: %d", typ)
138 138
 	}
139 139
 	e.Labels = nl.DecodeMPLSStack(buf[4:])
140 140
 	return nil
... ...
@@ -185,6 +186,79 @@ func (e *MPLSEncap) Equal(x Encap) bool {
185 185
 	return true
186 186
 }
187 187
 
188
+// SEG6 definitions
189
+type SEG6Encap struct {
190
+	Mode     int
191
+	Segments []net.IP
192
+}
193
+
194
+func (e *SEG6Encap) Type() int {
195
+	return nl.LWTUNNEL_ENCAP_SEG6
196
+}
197
+func (e *SEG6Encap) Decode(buf []byte) error {
198
+	if len(buf) < 4 {
199
+		return fmt.Errorf("lack of bytes")
200
+	}
201
+	native := nl.NativeEndian()
202
+	// Get Length(l) & Type(typ) : 2 + 2 bytes
203
+	l := native.Uint16(buf)
204
+	if len(buf) < int(l) {
205
+		return fmt.Errorf("lack of bytes")
206
+	}
207
+	buf = buf[:l] // make sure buf size upper limit is Length
208
+	typ := native.Uint16(buf[2:])
209
+	if typ != nl.SEG6_IPTUNNEL_SRH {
210
+		return fmt.Errorf("unknown SEG6 Type: %d", typ)
211
+	}
212
+
213
+	var err error
214
+	e.Mode, e.Segments, err = nl.DecodeSEG6Encap(buf[4:])
215
+
216
+	return err
217
+}
218
+func (e *SEG6Encap) Encode() ([]byte, error) {
219
+	s, err := nl.EncodeSEG6Encap(e.Mode, e.Segments)
220
+	native := nl.NativeEndian()
221
+	hdr := make([]byte, 4)
222
+	native.PutUint16(hdr, uint16(len(s)+4))
223
+	native.PutUint16(hdr[2:], nl.SEG6_IPTUNNEL_SRH)
224
+	return append(hdr, s...), err
225
+}
226
+func (e *SEG6Encap) String() string {
227
+	segs := make([]string, 0, len(e.Segments))
228
+	// append segment backwards (from n to 0) since seg#0 is the last segment.
229
+	for i := len(e.Segments); i > 0; i-- {
230
+		segs = append(segs, fmt.Sprintf("%s", e.Segments[i-1]))
231
+	}
232
+	str := fmt.Sprintf("mode %s segs %d [ %s ]", nl.SEG6EncapModeString(e.Mode),
233
+		len(e.Segments), strings.Join(segs, " "))
234
+	return str
235
+}
236
+func (e *SEG6Encap) Equal(x Encap) bool {
237
+	o, ok := x.(*SEG6Encap)
238
+	if !ok {
239
+		return false
240
+	}
241
+	if e == o {
242
+		return true
243
+	}
244
+	if e == nil || o == nil {
245
+		return false
246
+	}
247
+	if e.Mode != o.Mode {
248
+		return false
249
+	}
250
+	if len(e.Segments) != len(o.Segments) {
251
+		return false
252
+	}
253
+	for i := range e.Segments {
254
+		if !e.Segments[i].Equal(o.Segments[i]) {
255
+			return false
256
+		}
257
+	}
258
+	return true
259
+}
260
+
188 261
 // RouteAdd will add a route to the system.
189 262
 // Equivalent to: `ip route add $route`
190 263
 func RouteAdd(route *Route) error {
... ...
@@ -194,8 +268,8 @@ func RouteAdd(route *Route) error {
194 194
 // RouteAdd will add a route to the system.
195 195
 // Equivalent to: `ip route add $route`
196 196
 func (h *Handle) RouteAdd(route *Route) error {
197
-	flags := syscall.NLM_F_CREATE | syscall.NLM_F_EXCL | syscall.NLM_F_ACK
198
-	req := h.newNetlinkRequest(syscall.RTM_NEWROUTE, flags)
197
+	flags := unix.NLM_F_CREATE | unix.NLM_F_EXCL | unix.NLM_F_ACK
198
+	req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags)
199 199
 	return h.routeHandle(route, req, nl.NewRtMsg())
200 200
 }
201 201
 
... ...
@@ -208,8 +282,8 @@ func RouteReplace(route *Route) error {
208 208
 // RouteReplace will add a route to the system.
209 209
 // Equivalent to: `ip route replace $route`
210 210
 func (h *Handle) RouteReplace(route *Route) error {
211
-	flags := syscall.NLM_F_CREATE | syscall.NLM_F_REPLACE | syscall.NLM_F_ACK
212
-	req := h.newNetlinkRequest(syscall.RTM_NEWROUTE, flags)
211
+	flags := unix.NLM_F_CREATE | unix.NLM_F_REPLACE | unix.NLM_F_ACK
212
+	req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags)
213 213
 	return h.routeHandle(route, req, nl.NewRtMsg())
214 214
 }
215 215
 
... ...
@@ -222,7 +296,7 @@ func RouteDel(route *Route) error {
222 222
 // RouteDel will delete a route from the system.
223 223
 // Equivalent to: `ip route del $route`
224 224
 func (h *Handle) RouteDel(route *Route) error {
225
-	req := h.newNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK)
225
+	req := h.newNetlinkRequest(unix.RTM_DELROUTE, unix.NLM_F_ACK)
226 226
 	return h.routeHandle(route, req, nl.NewRtDelMsg())
227 227
 }
228 228
 
... ...
@@ -245,12 +319,12 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
245 245
 		} else {
246 246
 			dstData = route.Dst.IP.To16()
247 247
 		}
248
-		rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, dstData))
248
+		rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, dstData))
249 249
 	} else if route.MPLSDst != nil {
250 250
 		family = nl.FAMILY_MPLS
251 251
 		msg.Dst_len = uint8(20)
252
-		msg.Type = syscall.RTN_UNICAST
253
-		rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, nl.EncodeMPLSStack(*route.MPLSDst)))
252
+		msg.Type = unix.RTN_UNICAST
253
+		rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, nl.EncodeMPLSStack(*route.MPLSDst)))
254 254
 	}
255 255
 
256 256
 	if route.NewDst != nil {
... ...
@@ -288,7 +362,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
288 288
 			srcData = route.Src.To16()
289 289
 		}
290 290
 		// The commonly used src ip for routes is actually PREFSRC
291
-		rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PREFSRC, srcData))
291
+		rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_PREFSRC, srcData))
292 292
 	}
293 293
 
294 294
 	if route.Gw != nil {
... ...
@@ -303,14 +377,14 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
303 303
 		} else {
304 304
 			gwData = route.Gw.To16()
305 305
 		}
306
-		rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_GATEWAY, gwData))
306
+		rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_GATEWAY, gwData))
307 307
 	}
308 308
 
309 309
 	if len(route.MultiPath) > 0 {
310 310
 		buf := []byte{}
311 311
 		for _, nh := range route.MultiPath {
312 312
 			rtnh := &nl.RtNexthop{
313
-				RtNexthop: syscall.RtNexthop{
313
+				RtNexthop: unix.RtNexthop{
314 314
 					Hops:    uint8(nh.Hops),
315 315
 					Ifindex: int32(nh.LinkIndex),
316 316
 					Flags:   uint8(nh.Flags),
... ...
@@ -323,9 +397,9 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
323 323
 					return fmt.Errorf("gateway, source, and destination ip are not the same IP family")
324 324
 				}
325 325
 				if gwFamily == FAMILY_V4 {
326
-					children = append(children, nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To4())))
326
+					children = append(children, nl.NewRtAttr(unix.RTA_GATEWAY, []byte(nh.Gw.To4())))
327 327
 				} else {
328
-					children = append(children, nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To16())))
328
+					children = append(children, nl.NewRtAttr(unix.RTA_GATEWAY, []byte(nh.Gw.To16())))
329 329
 				}
330 330
 			}
331 331
 			if nh.NewDst != nil {
... ...
@@ -351,15 +425,15 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
351 351
 			rtnh.Children = children
352 352
 			buf = append(buf, rtnh.Serialize()...)
353 353
 		}
354
-		rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_MULTIPATH, buf))
354
+		rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_MULTIPATH, buf))
355 355
 	}
356 356
 
357 357
 	if route.Table > 0 {
358 358
 		if route.Table >= 256 {
359
-			msg.Table = syscall.RT_TABLE_UNSPEC
359
+			msg.Table = unix.RT_TABLE_UNSPEC
360 360
 			b := make([]byte, 4)
361 361
 			native.PutUint32(b, uint32(route.Table))
362
-			rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_TABLE, b))
362
+			rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_TABLE, b))
363 363
 		} else {
364 364
 			msg.Table = uint8(route.Table)
365 365
 		}
... ...
@@ -368,7 +442,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
368 368
 	if route.Priority > 0 {
369 369
 		b := make([]byte, 4)
370 370
 		native.PutUint32(b, uint32(route.Priority))
371
-		rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PRIORITY, b))
371
+		rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_PRIORITY, b))
372 372
 	}
373 373
 	if route.Tos > 0 {
374 374
 		msg.Tos = uint8(route.Tos)
... ...
@@ -380,6 +454,25 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
380 380
 		msg.Type = uint8(route.Type)
381 381
 	}
382 382
 
383
+	var metrics []*nl.RtAttr
384
+	// TODO: support other rta_metric values
385
+	if route.MTU > 0 {
386
+		b := nl.Uint32Attr(uint32(route.MTU))
387
+		metrics = append(metrics, nl.NewRtAttr(unix.RTAX_MTU, b))
388
+	}
389
+	if route.AdvMSS > 0 {
390
+		b := nl.Uint32Attr(uint32(route.AdvMSS))
391
+		metrics = append(metrics, nl.NewRtAttr(unix.RTAX_ADVMSS, b))
392
+	}
393
+
394
+	if metrics != nil {
395
+		attr := nl.NewRtAttr(unix.RTA_METRICS, nil)
396
+		for _, metric := range metrics {
397
+			attr.AddChild(metric)
398
+		}
399
+		rtAttrs = append(rtAttrs, attr)
400
+	}
401
+
383 402
 	msg.Flags = uint32(route.Flags)
384 403
 	msg.Scope = uint8(route.Scope)
385 404
 	msg.Family = uint8(family)
... ...
@@ -394,9 +487,9 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
394 394
 	)
395 395
 	native.PutUint32(b, uint32(route.LinkIndex))
396 396
 
397
-	req.AddData(nl.NewRtAttr(syscall.RTA_OIF, b))
397
+	req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
398 398
 
399
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
399
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
400 400
 	return err
401 401
 }
402 402
 
... ...
@@ -429,11 +522,11 @@ func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, e
429 429
 // RouteListFiltered gets a list of routes in the system filtered with specified rules.
430 430
 // All rules must be defined in RouteFilter struct
431 431
 func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
432
-	req := h.newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP)
432
+	req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_DUMP)
433 433
 	infmsg := nl.NewIfInfomsg(family)
434 434
 	req.AddData(infmsg)
435 435
 
436
-	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE)
436
+	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE)
437 437
 	if err != nil {
438 438
 		return nil, err
439 439
 	}
... ...
@@ -441,11 +534,11 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
441 441
 	var res []Route
442 442
 	for _, m := range msgs {
443 443
 		msg := nl.DeserializeRtMsg(m)
444
-		if msg.Flags&syscall.RTM_F_CLONED != 0 {
444
+		if msg.Flags&unix.RTM_F_CLONED != 0 {
445 445
 			// Ignore cloned routes
446 446
 			continue
447 447
 		}
448
-		if msg.Table != syscall.RT_TABLE_MAIN {
448
+		if msg.Table != unix.RT_TABLE_MAIN {
449 449
 			if filter == nil || filter != nil && filterMask&RT_FILTER_TABLE == 0 {
450 450
 				// Ignore non-main tables
451 451
 				continue
... ...
@@ -457,7 +550,7 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
457 457
 		}
458 458
 		if filter != nil {
459 459
 			switch {
460
-			case filterMask&RT_FILTER_TABLE != 0 && filter.Table != syscall.RT_TABLE_UNSPEC && route.Table != filter.Table:
460
+			case filterMask&RT_FILTER_TABLE != 0 && filter.Table != unix.RT_TABLE_UNSPEC && route.Table != filter.Table:
461 461
 				continue
462 462
 			case filterMask&RT_FILTER_PROTOCOL != 0 && route.Protocol != filter.Protocol:
463 463
 				continue
... ...
@@ -508,11 +601,11 @@ func deserializeRoute(m []byte) (Route, error) {
508 508
 	var encap, encapType syscall.NetlinkRouteAttr
509 509
 	for _, attr := range attrs {
510 510
 		switch attr.Attr.Type {
511
-		case syscall.RTA_GATEWAY:
511
+		case unix.RTA_GATEWAY:
512 512
 			route.Gw = net.IP(attr.Value)
513
-		case syscall.RTA_PREFSRC:
513
+		case unix.RTA_PREFSRC:
514 514
 			route.Src = net.IP(attr.Value)
515
-		case syscall.RTA_DST:
515
+		case unix.RTA_DST:
516 516
 			if msg.Family == nl.FAMILY_MPLS {
517 517
 				stack := nl.DecodeMPLSStack(attr.Value)
518 518
 				if len(stack) == 0 || len(stack) > 1 {
... ...
@@ -525,36 +618,36 @@ func deserializeRoute(m []byte) (Route, error) {
525 525
 					Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)),
526 526
 				}
527 527
 			}
528
-		case syscall.RTA_OIF:
528
+		case unix.RTA_OIF:
529 529
 			route.LinkIndex = int(native.Uint32(attr.Value[0:4]))
530
-		case syscall.RTA_IIF:
530
+		case unix.RTA_IIF:
531 531
 			route.ILinkIndex = int(native.Uint32(attr.Value[0:4]))
532
-		case syscall.RTA_PRIORITY:
532
+		case unix.RTA_PRIORITY:
533 533
 			route.Priority = int(native.Uint32(attr.Value[0:4]))
534
-		case syscall.RTA_TABLE:
534
+		case unix.RTA_TABLE:
535 535
 			route.Table = int(native.Uint32(attr.Value[0:4]))
536
-		case syscall.RTA_MULTIPATH:
536
+		case unix.RTA_MULTIPATH:
537 537
 			parseRtNexthop := func(value []byte) (*NexthopInfo, []byte, error) {
538
-				if len(value) < syscall.SizeofRtNexthop {
539
-					return nil, nil, fmt.Errorf("Lack of bytes")
538
+				if len(value) < unix.SizeofRtNexthop {
539
+					return nil, nil, fmt.Errorf("lack of bytes")
540 540
 				}
541 541
 				nh := nl.DeserializeRtNexthop(value)
542 542
 				if len(value) < int(nh.RtNexthop.Len) {
543
-					return nil, nil, fmt.Errorf("Lack of bytes")
543
+					return nil, nil, fmt.Errorf("lack of bytes")
544 544
 				}
545 545
 				info := &NexthopInfo{
546 546
 					LinkIndex: int(nh.RtNexthop.Ifindex),
547 547
 					Hops:      int(nh.RtNexthop.Hops),
548 548
 					Flags:     int(nh.RtNexthop.Flags),
549 549
 				}
550
-				attrs, err := nl.ParseRouteAttr(value[syscall.SizeofRtNexthop:int(nh.RtNexthop.Len)])
550
+				attrs, err := nl.ParseRouteAttr(value[unix.SizeofRtNexthop:int(nh.RtNexthop.Len)])
551 551
 				if err != nil {
552 552
 					return nil, nil, err
553 553
 				}
554 554
 				var encap, encapType syscall.NetlinkRouteAttr
555 555
 				for _, attr := range attrs {
556 556
 					switch attr.Attr.Type {
557
-					case syscall.RTA_GATEWAY:
557
+					case unix.RTA_GATEWAY:
558 558
 						info.Gw = net.IP(attr.Value)
559 559
 					case nl.RTA_NEWDST:
560 560
 						var d Destination
... ...
@@ -611,6 +704,19 @@ func deserializeRoute(m []byte) (Route, error) {
611 611
 			encapType = attr
612 612
 		case nl.RTA_ENCAP:
613 613
 			encap = attr
614
+		case unix.RTA_METRICS:
615
+			metrics, err := nl.ParseRouteAttr(attr.Value)
616
+			if err != nil {
617
+				return route, err
618
+			}
619
+			for _, metric := range metrics {
620
+				switch metric.Attr.Type {
621
+				case unix.RTAX_MTU:
622
+					route.MTU = int(native.Uint32(metric.Value[0:4]))
623
+				case unix.RTAX_ADVMSS:
624
+					route.AdvMSS = int(native.Uint32(metric.Value[0:4]))
625
+				}
626
+			}
614 627
 		}
615 628
 	}
616 629
 
... ...
@@ -623,6 +729,11 @@ func deserializeRoute(m []byte) (Route, error) {
623 623
 			if err := e.Decode(encap.Value); err != nil {
624 624
 				return route, err
625 625
 			}
626
+		case nl.LWTUNNEL_ENCAP_SEG6:
627
+			e = &SEG6Encap{}
628
+			if err := e.Decode(encap.Value); err != nil {
629
+				return route, err
630
+			}
626 631
 		}
627 632
 		route.Encap = e
628 633
 	}
... ...
@@ -639,7 +750,7 @@ func RouteGet(destination net.IP) ([]Route, error) {
639 639
 // RouteGet gets a route to a specific destination from the host system.
640 640
 // Equivalent to: 'ip route get'.
641 641
 func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
642
-	req := h.newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_REQUEST)
642
+	req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_REQUEST)
643 643
 	family := nl.GetIPFamily(destination)
644 644
 	var destinationData []byte
645 645
 	var bitlen uint8
... ...
@@ -655,10 +766,10 @@ func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
655 655
 	msg.Dst_len = bitlen
656 656
 	req.AddData(msg)
657 657
 
658
-	rtaDst := nl.NewRtAttr(syscall.RTA_DST, destinationData)
658
+	rtaDst := nl.NewRtAttr(unix.RTA_DST, destinationData)
659 659
 	req.AddData(rtaDst)
660 660
 
661
-	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE)
661
+	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE)
662 662
 	if err != nil {
663 663
 		return nil, err
664 664
 	}
... ...
@@ -678,13 +789,13 @@ func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
678 678
 // RouteSubscribe takes a chan down which notifications will be sent
679 679
 // when routes are added or deleted. Close the 'done' chan to stop subscription.
680 680
 func RouteSubscribe(ch chan<- RouteUpdate, done <-chan struct{}) error {
681
-	return routeSubscribeAt(netns.None(), netns.None(), ch, done, nil)
681
+	return routeSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
682 682
 }
683 683
 
684 684
 // RouteSubscribeAt works like RouteSubscribe plus it allows the caller
685 685
 // to choose the network namespace in which to subscribe (ns).
686 686
 func RouteSubscribeAt(ns netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}) error {
687
-	return routeSubscribeAt(ns, netns.None(), ch, done, nil)
687
+	return routeSubscribeAt(ns, netns.None(), ch, done, nil, false)
688 688
 }
689 689
 
690 690
 // RouteSubscribeOptions contains a set of options to use with
... ...
@@ -692,6 +803,7 @@ func RouteSubscribeAt(ns netns.NsHandle, ch chan<- RouteUpdate, done <-chan stru
692 692
 type RouteSubscribeOptions struct {
693 693
 	Namespace     *netns.NsHandle
694 694
 	ErrorCallback func(error)
695
+	ListExisting  bool
695 696
 }
696 697
 
697 698
 // RouteSubscribeWithOptions work like RouteSubscribe but enable to
... ...
@@ -702,11 +814,11 @@ func RouteSubscribeWithOptions(ch chan<- RouteUpdate, done <-chan struct{}, opti
702 702
 		none := netns.None()
703 703
 		options.Namespace = &none
704 704
 	}
705
-	return routeSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback)
705
+	return routeSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
706 706
 }
707 707
 
708
-func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}, cberr func(error)) error {
709
-	s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_ROUTE, syscall.RTNLGRP_IPV6_ROUTE)
708
+func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
709
+	s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_ROUTE, unix.RTNLGRP_IPV6_ROUTE)
710 710
 	if err != nil {
711 711
 		return err
712 712
 	}
... ...
@@ -716,6 +828,15 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
716 716
 			s.Close()
717 717
 		}()
718 718
 	}
719
+	if listExisting {
720
+		req := pkgHandle.newNetlinkRequest(unix.RTM_GETROUTE,
721
+			unix.NLM_F_DUMP)
722
+		infmsg := nl.NewIfInfomsg(unix.AF_UNSPEC)
723
+		req.AddData(infmsg)
724
+		if err := s.Send(req); err != nil {
725
+			return err
726
+		}
727
+	}
719 728
 	go func() {
720 729
 		defer close(ch)
721 730
 		for {
... ...
@@ -727,6 +848,20 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
727 727
 				return
728 728
 			}
729 729
 			for _, m := range msgs {
730
+				if m.Header.Type == unix.NLMSG_DONE {
731
+					continue
732
+				}
733
+				if m.Header.Type == unix.NLMSG_ERROR {
734
+					native := nl.NativeEndian()
735
+					error := int32(native.Uint32(m.Data[0:4]))
736
+					if error == 0 {
737
+						continue
738
+					}
739
+					if cberr != nil {
740
+						cberr(syscall.Errno(-error))
741
+					}
742
+					return
743
+				}
730 744
 				route, err := deserializeRoute(m.Data)
731 745
 				if err != nil {
732 746
 					if cberr != nil {
... ...
@@ -21,6 +21,7 @@ type Rule struct {
21 21
 	OifName           string
22 22
 	SuppressIfgroup   int
23 23
 	SuppressPrefixlen int
24
+	Invert            bool
24 25
 }
25 26
 
26 27
 func (r Rule) String() string {
... ...
@@ -3,11 +3,13 @@ package netlink
3 3
 import (
4 4
 	"fmt"
5 5
 	"net"
6
-	"syscall"
7 6
 
8 7
 	"github.com/vishvananda/netlink/nl"
8
+	"golang.org/x/sys/unix"
9 9
 )
10 10
 
11
+const FibRuleInvert = 0x2
12
+
11 13
 // RuleAdd adds a rule to the system.
12 14
 // Equivalent to: ip rule add
13 15
 func RuleAdd(rule *Rule) error {
... ...
@@ -17,7 +19,7 @@ func RuleAdd(rule *Rule) error {
17 17
 // RuleAdd adds a rule to the system.
18 18
 // Equivalent to: ip rule add
19 19
 func (h *Handle) RuleAdd(rule *Rule) error {
20
-	req := h.newNetlinkRequest(syscall.RTM_NEWRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
20
+	req := h.newNetlinkRequest(unix.RTM_NEWRULE, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
21 21
 	return ruleHandle(rule, req)
22 22
 }
23 23
 
... ...
@@ -30,18 +32,31 @@ func RuleDel(rule *Rule) error {
30 30
 // RuleDel deletes a rule from the system.
31 31
 // Equivalent to: ip rule del
32 32
 func (h *Handle) RuleDel(rule *Rule) error {
33
-	req := h.newNetlinkRequest(syscall.RTM_DELRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
33
+	req := h.newNetlinkRequest(unix.RTM_DELRULE, unix.NLM_F_ACK)
34 34
 	return ruleHandle(rule, req)
35 35
 }
36 36
 
37 37
 func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
38 38
 	msg := nl.NewRtMsg()
39
-	msg.Family = syscall.AF_INET
39
+	msg.Family = unix.AF_INET
40
+	msg.Protocol = unix.RTPROT_BOOT
41
+	msg.Scope = unix.RT_SCOPE_UNIVERSE
42
+	msg.Table = unix.RT_TABLE_UNSPEC
43
+	msg.Type = unix.RTN_UNSPEC
44
+	if req.NlMsghdr.Flags&unix.NLM_F_CREATE > 0 {
45
+		msg.Type = unix.RTN_UNICAST
46
+	}
47
+	if rule.Invert {
48
+		msg.Flags |= FibRuleInvert
49
+	}
40 50
 	if rule.Family != 0 {
41 51
 		msg.Family = uint8(rule.Family)
42 52
 	}
43
-	var dstFamily uint8
53
+	if rule.Table >= 0 && rule.Table < 256 {
54
+		msg.Table = uint8(rule.Table)
55
+	}
44 56
 
57
+	var dstFamily uint8
45 58
 	var rtAttrs []*nl.RtAttr
46 59
 	if rule.Dst != nil && rule.Dst.IP != nil {
47 60
 		dstLen, _ := rule.Dst.Mask.Size()
... ...
@@ -49,12 +64,12 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
49 49
 		msg.Family = uint8(nl.GetIPFamily(rule.Dst.IP))
50 50
 		dstFamily = msg.Family
51 51
 		var dstData []byte
52
-		if msg.Family == syscall.AF_INET {
52
+		if msg.Family == unix.AF_INET {
53 53
 			dstData = rule.Dst.IP.To4()
54 54
 		} else {
55 55
 			dstData = rule.Dst.IP.To16()
56 56
 		}
57
-		rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, dstData))
57
+		rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, dstData))
58 58
 	}
59 59
 
60 60
 	if rule.Src != nil && rule.Src.IP != nil {
... ...
@@ -65,19 +80,12 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
65 65
 		srcLen, _ := rule.Src.Mask.Size()
66 66
 		msg.Src_len = uint8(srcLen)
67 67
 		var srcData []byte
68
-		if msg.Family == syscall.AF_INET {
68
+		if msg.Family == unix.AF_INET {
69 69
 			srcData = rule.Src.IP.To4()
70 70
 		} else {
71 71
 			srcData = rule.Src.IP.To16()
72 72
 		}
73
-		rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_SRC, srcData))
74
-	}
75
-
76
-	if rule.Table >= 0 {
77
-		msg.Table = uint8(rule.Table)
78
-		if rule.Table >= 256 {
79
-			msg.Table = syscall.RT_TABLE_UNSPEC
80
-		}
73
+		rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_SRC, srcData))
81 74
 	}
82 75
 
83 76
 	req.AddData(msg)
... ...
@@ -142,7 +150,7 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
142 142
 		req.AddData(nl.NewRtAttr(nl.FRA_GOTO, b))
143 143
 	}
144 144
 
145
-	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
145
+	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
146 146
 	return err
147 147
 }
148 148
 
... ...
@@ -155,11 +163,11 @@ func RuleList(family int) ([]Rule, error) {
155 155
 // RuleList lists rules in the system.
156 156
 // Equivalent to: ip rule list
157 157
 func (h *Handle) RuleList(family int) ([]Rule, error) {
158
-	req := h.newNetlinkRequest(syscall.RTM_GETRULE, syscall.NLM_F_DUMP|syscall.NLM_F_REQUEST)
158
+	req := h.newNetlinkRequest(unix.RTM_GETRULE, unix.NLM_F_DUMP|unix.NLM_F_REQUEST)
159 159
 	msg := nl.NewIfInfomsg(family)
160 160
 	req.AddData(msg)
161 161
 
162
-	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWRULE)
162
+	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWRULE)
163 163
 	if err != nil {
164 164
 		return nil, err
165 165
 	}
... ...
@@ -175,9 +183,11 @@ func (h *Handle) RuleList(family int) ([]Rule, error) {
175 175
 
176 176
 		rule := NewRule()
177 177
 
178
+		rule.Invert = msg.Flags&FibRuleInvert > 0
179
+
178 180
 		for j := range attrs {
179 181
 			switch attrs[j].Attr.Type {
180
-			case syscall.RTA_TABLE:
182
+			case unix.RTA_TABLE:
181 183
 				rule.Table = int(native.Uint32(attrs[j].Value[0:4]))
182 184
 			case nl.FRA_SRC:
183 185
 				rule.Src = &net.IPNet{
... ...
@@ -4,9 +4,9 @@ import (
4 4
 	"errors"
5 5
 	"fmt"
6 6
 	"net"
7
-	"syscall"
8 7
 
9 8
 	"github.com/vishvananda/netlink/nl"
9
+	"golang.org/x/sys/unix"
10 10
 )
11 11
 
12 12
 const (
... ...
@@ -123,15 +123,15 @@ func SocketGet(local, remote net.Addr) (*Socket, error) {
123 123
 		return nil, ErrNotImplemented
124 124
 	}
125 125
 
126
-	s, err := nl.Subscribe(syscall.NETLINK_INET_DIAG)
126
+	s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
127 127
 	if err != nil {
128 128
 		return nil, err
129 129
 	}
130 130
 	defer s.Close()
131 131
 	req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, 0)
132 132
 	req.AddData(&socketRequest{
133
-		Family:   syscall.AF_INET,
134
-		Protocol: syscall.IPPROTO_TCP,
133
+		Family:   unix.AF_INET,
134
+		Protocol: unix.IPPROTO_TCP,
135 135
 		ID: SocketID{
136 136
 			SourcePort:      uint16(localTCP.Port),
137 137
 			DestinationPort: uint16(remoteTCP.Port),
... ...
@@ -2,19 +2,20 @@ package netlink
2 2
 
3 3
 import (
4 4
 	"fmt"
5
-	"syscall"
5
+
6
+	"golang.org/x/sys/unix"
6 7
 )
7 8
 
8 9
 // Proto is an enum representing an ipsec protocol.
9 10
 type Proto uint8
10 11
 
11 12
 const (
12
-	XFRM_PROTO_ROUTE2    Proto = syscall.IPPROTO_ROUTING
13
-	XFRM_PROTO_ESP       Proto = syscall.IPPROTO_ESP
14
-	XFRM_PROTO_AH        Proto = syscall.IPPROTO_AH
15
-	XFRM_PROTO_HAO       Proto = syscall.IPPROTO_DSTOPTS
13
+	XFRM_PROTO_ROUTE2    Proto = unix.IPPROTO_ROUTING
14
+	XFRM_PROTO_ESP       Proto = unix.IPPROTO_ESP
15
+	XFRM_PROTO_AH        Proto = unix.IPPROTO_AH
16
+	XFRM_PROTO_HAO       Proto = unix.IPPROTO_DSTOPTS
16 17
 	XFRM_PROTO_COMP      Proto = 0x6c // NOTE not defined on darwin
17
-	XFRM_PROTO_IPSEC_ANY Proto = syscall.IPPROTO_RAW
18
+	XFRM_PROTO_IPSEC_ANY Proto = unix.IPPROTO_RAW
18 19
 )
19 20
 
20 21
 func (p Proto) String() string {
... ...
@@ -2,11 +2,10 @@ package netlink
2 2
 
3 3
 import (
4 4
 	"fmt"
5
-	"syscall"
6
-
7
-	"github.com/vishvananda/netns"
8 5
 
9 6
 	"github.com/vishvananda/netlink/nl"
7
+	"github.com/vishvananda/netns"
8
+	"golang.org/x/sys/unix"
10 9
 )
11 10
 
12 11
 type XfrmMsg interface {
... ...
@@ -39,7 +38,7 @@ func XfrmMonitor(ch chan<- XfrmMsg, done <-chan struct{}, errorChan chan<- error
39 39
 	if err != nil {
40 40
 		return nil
41 41
 	}
42
-	s, err := nl.SubscribeAt(netns.None(), netns.None(), syscall.NETLINK_XFRM, groups...)
42
+	s, err := nl.SubscribeAt(netns.None(), netns.None(), unix.NETLINK_XFRM, groups...)
43 43
 	if err != nil {
44 44
 		return err
45 45
 	}
... ...
@@ -1,9 +1,8 @@
1 1
 package netlink
2 2
 
3 3
 import (
4
-	"syscall"
5
-
6 4
 	"github.com/vishvananda/netlink/nl"
5
+	"golang.org/x/sys/unix"
7 6
 )
8 7
 
9 8
 func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) {
... ...
@@ -55,7 +54,7 @@ func (h *Handle) XfrmPolicyUpdate(policy *XfrmPolicy) error {
55 55
 }
56 56
 
57 57
 func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
58
-	req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
58
+	req := h.newNetlinkRequest(nlProto, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
59 59
 
60 60
 	msg := &nl.XfrmUserpolicyInfo{}
61 61
 	selFromPolicy(&msg.Sel, policy)
... ...
@@ -91,7 +90,7 @@ func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
91 91
 		req.AddData(out)
92 92
 	}
93 93
 
94
-	_, err := req.Execute(syscall.NETLINK_XFRM, 0)
94
+	_, err := req.Execute(unix.NETLINK_XFRM, 0)
95 95
 	return err
96 96
 }
97 97
 
... ...
@@ -121,12 +120,12 @@ func XfrmPolicyList(family int) ([]XfrmPolicy, error) {
121 121
 // Equivalent to: `ip xfrm policy show`.
122 122
 // The list can be filtered by ip family.
123 123
 func (h *Handle) XfrmPolicyList(family int) ([]XfrmPolicy, error) {
124
-	req := h.newNetlinkRequest(nl.XFRM_MSG_GETPOLICY, syscall.NLM_F_DUMP)
124
+	req := h.newNetlinkRequest(nl.XFRM_MSG_GETPOLICY, unix.NLM_F_DUMP)
125 125
 
126 126
 	msg := nl.NewIfInfomsg(family)
127 127
 	req.AddData(msg)
128 128
 
129
-	msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY)
129
+	msgs, err := req.Execute(unix.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY)
130 130
 	if err != nil {
131 131
 		return nil, err
132 132
 	}
... ...
@@ -165,13 +164,13 @@ func XfrmPolicyFlush() error {
165 165
 // XfrmPolicyFlush will flush the policies on the system.
166 166
 // Equivalent to: `ip xfrm policy flush`
167 167
 func (h *Handle) XfrmPolicyFlush() error {
168
-	req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHPOLICY, syscall.NLM_F_ACK)
169
-	_, err := req.Execute(syscall.NETLINK_XFRM, 0)
168
+	req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHPOLICY, unix.NLM_F_ACK)
169
+	_, err := req.Execute(unix.NETLINK_XFRM, 0)
170 170
 	return err
171 171
 }
172 172
 
173 173
 func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPolicy, error) {
174
-	req := h.newNetlinkRequest(nlProto, syscall.NLM_F_ACK)
174
+	req := h.newNetlinkRequest(nlProto, unix.NLM_F_ACK)
175 175
 
176 176
 	msg := &nl.XfrmUserpolicyId{}
177 177
 	selFromPolicy(&msg.Sel, policy)
... ...
@@ -189,7 +188,7 @@ func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPo
189 189
 		resType = 0
190 190
 	}
191 191
 
192
-	msgs, err := req.Execute(syscall.NETLINK_XFRM, uint16(resType))
192
+	msgs, err := req.Execute(unix.NETLINK_XFRM, uint16(resType))
193 193
 	if err != nil {
194 194
 		return nil, err
195 195
 	}
... ...
@@ -3,6 +3,7 @@ package netlink
3 3
 import (
4 4
 	"fmt"
5 5
 	"net"
6
+	"time"
6 7
 )
7 8
 
8 9
 // XfrmStateAlgo represents the algorithm to use for the ipsec encryption.
... ...
@@ -67,6 +68,19 @@ type XfrmStateLimits struct {
67 67
 	TimeUseHard uint64
68 68
 }
69 69
 
70
+// XfrmStateStats represents the current number of bytes/packets
71
+// processed by this State, the State's installation and first use
72
+// time and the replay window counters.
73
+type XfrmStateStats struct {
74
+	ReplayWindow uint32
75
+	Replay       uint32
76
+	Failed       uint32
77
+	Bytes        uint64
78
+	Packets      uint64
79
+	AddTime      uint64
80
+	UseTime      uint64
81
+}
82
+
70 83
 // XfrmState represents the state of an ipsec policy. It optionally
71 84
 // contains an XfrmStateAlgo for encryption and one for authentication.
72 85
 type XfrmState struct {
... ...
@@ -78,6 +92,7 @@ type XfrmState struct {
78 78
 	Reqid        int
79 79
 	ReplayWindow int
80 80
 	Limits       XfrmStateLimits
81
+	Statistics   XfrmStateStats
81 82
 	Mark         *XfrmMark
82 83
 	Auth         *XfrmStateAlgo
83 84
 	Crypt        *XfrmStateAlgo
... ...
@@ -94,10 +109,16 @@ func (sa XfrmState) Print(stats bool) string {
94 94
 	if !stats {
95 95
 		return sa.String()
96 96
 	}
97
-
98
-	return fmt.Sprintf("%s, ByteSoft: %s, ByteHard: %s, PacketSoft: %s, PacketHard: %s, TimeSoft: %d, TimeHard: %d, TimeUseSoft: %d, TimeUseHard: %d",
97
+	at := time.Unix(int64(sa.Statistics.AddTime), 0).Format(time.UnixDate)
98
+	ut := "-"
99
+	if sa.Statistics.UseTime > 0 {
100
+		ut = time.Unix(int64(sa.Statistics.UseTime), 0).Format(time.UnixDate)
101
+	}
102
+	return fmt.Sprintf("%s, ByteSoft: %s, ByteHard: %s, PacketSoft: %s, PacketHard: %s, TimeSoft: %d, TimeHard: %d, TimeUseSoft: %d, TimeUseHard: %d, Bytes: %d, Packets: %d, "+
103
+		"AddTime: %s, UseTime: %s, ReplayWindow: %d, Replay: %d, Failed: %d",
99 104
 		sa.String(), printLimit(sa.Limits.ByteSoft), printLimit(sa.Limits.ByteHard), printLimit(sa.Limits.PacketSoft), printLimit(sa.Limits.PacketHard),
100
-		sa.Limits.TimeSoft, sa.Limits.TimeHard, sa.Limits.TimeUseSoft, sa.Limits.TimeUseHard)
105
+		sa.Limits.TimeSoft, sa.Limits.TimeHard, sa.Limits.TimeUseSoft, sa.Limits.TimeUseHard, sa.Statistics.Bytes, sa.Statistics.Packets, at, ut,
106
+		sa.Statistics.ReplayWindow, sa.Statistics.Replay, sa.Statistics.Failed)
101 107
 }
102 108
 
103 109
 func printLimit(lmt uint64) string {
... ...
@@ -2,10 +2,10 @@ package netlink
2 2
 
3 3
 import (
4 4
 	"fmt"
5
-	"syscall"
6 5
 	"unsafe"
7 6
 
8 7
 	"github.com/vishvananda/netlink/nl"
8
+	"golang.org/x/sys/unix"
9 9
 )
10 10
 
11 11
 func writeStateAlgo(a *XfrmStateAlgo) []byte {
... ...
@@ -69,8 +69,10 @@ func writeReplayEsn(replayWindow int) []byte {
69 69
 		ReplayWindow: uint32(replayWindow),
70 70
 	}
71 71
 
72
-	// taken from iproute2/ip/xfrm_state.c:
73
-	replayEsn.BmpLen = uint32((replayWindow + (4 * 8) - 1) / (4 * 8))
72
+	// Linux stores the bitmap to identify the already received sequence packets in blocks of uint32 elements.
73
+	// Therefore bitmap length is the minimum number of uint32 elements needed. The following is a ceiling operation.
74
+	bytesPerElem := int(unsafe.Sizeof(replayEsn.BmpLen)) // Any uint32 variable is good for this
75
+	replayEsn.BmpLen = uint32((replayWindow + (bytesPerElem * 8) - 1) / (bytesPerElem * 8))
74 76
 
75 77
 	return replayEsn.Serialize()
76 78
 }
... ...
@@ -111,7 +113,7 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
111 111
 	if state.Spi == 0 {
112 112
 		return fmt.Errorf("Spi must be set when adding xfrm state.")
113 113
 	}
114
-	req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
114
+	req := h.newNetlinkRequest(nlProto, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
115 115
 
116 116
 	msg := xfrmUsersaInfoFromXfrmState(state)
117 117
 
... ...
@@ -157,13 +159,13 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
157 157
 		req.AddData(out)
158 158
 	}
159 159
 
160
-	_, err := req.Execute(syscall.NETLINK_XFRM, 0)
160
+	_, err := req.Execute(unix.NETLINK_XFRM, 0)
161 161
 	return err
162 162
 }
163 163
 
164 164
 func (h *Handle) xfrmStateAllocSpi(state *XfrmState) (*XfrmState, error) {
165 165
 	req := h.newNetlinkRequest(nl.XFRM_MSG_ALLOCSPI,
166
-		syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
166
+		unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
167 167
 
168 168
 	msg := &nl.XfrmUserSpiInfo{}
169 169
 	msg.XfrmUsersaInfo = *(xfrmUsersaInfoFromXfrmState(state))
... ...
@@ -177,7 +179,7 @@ func (h *Handle) xfrmStateAllocSpi(state *XfrmState) (*XfrmState, error) {
177 177
 		req.AddData(out)
178 178
 	}
179 179
 
180
-	msgs, err := req.Execute(syscall.NETLINK_XFRM, 0)
180
+	msgs, err := req.Execute(unix.NETLINK_XFRM, 0)
181 181
 	if err != nil {
182 182
 		return nil, err
183 183
 	}
... ...
@@ -216,9 +218,9 @@ func XfrmStateList(family int) ([]XfrmState, error) {
216 216
 // Equivalent to: `ip xfrm state show`.
217 217
 // The list can be filtered by ip family.
218 218
 func (h *Handle) XfrmStateList(family int) ([]XfrmState, error) {
219
-	req := h.newNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP)
219
+	req := h.newNetlinkRequest(nl.XFRM_MSG_GETSA, unix.NLM_F_DUMP)
220 220
 
221
-	msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
221
+	msgs, err := req.Execute(unix.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
222 222
 	if err != nil {
223 223
 		return nil, err
224 224
 	}
... ...
@@ -255,7 +257,7 @@ func (h *Handle) XfrmStateGet(state *XfrmState) (*XfrmState, error) {
255 255
 }
256 256
 
257 257
 func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState, error) {
258
-	req := h.newNetlinkRequest(nlProto, syscall.NLM_F_ACK)
258
+	req := h.newNetlinkRequest(nlProto, unix.NLM_F_ACK)
259 259
 
260 260
 	msg := &nl.XfrmUsersaId{}
261 261
 	msg.Family = uint16(nl.GetIPFamily(state.Dst))
... ...
@@ -278,7 +280,7 @@ func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState
278 278
 		resType = 0
279 279
 	}
280 280
 
281
-	msgs, err := req.Execute(syscall.NETLINK_XFRM, uint16(resType))
281
+	msgs, err := req.Execute(unix.NETLINK_XFRM, uint16(resType))
282 282
 	if err != nil {
283 283
 		return nil, err
284 284
 	}
... ...
@@ -308,6 +310,7 @@ func xfrmStateFromXfrmUsersaInfo(msg *nl.XfrmUsersaInfo) *XfrmState {
308 308
 	state.Reqid = int(msg.Reqid)
309 309
 	state.ReplayWindow = int(msg.ReplayWindow)
310 310
 	lftToLimits(&msg.Lft, &state.Limits)
311
+	curToStats(&msg.Curlft, &msg.Stats, &state.Statistics)
311 312
 
312 313
 	return &state
313 314
 }
... ...
@@ -386,11 +389,11 @@ func XfrmStateFlush(proto Proto) error {
386 386
 // proto = 0 means any transformation protocols
387 387
 // Equivalent to: `ip xfrm state flush [ proto XFRM-PROTO ]`
388 388
 func (h *Handle) XfrmStateFlush(proto Proto) error {
389
-	req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHSA, syscall.NLM_F_ACK)
389
+	req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHSA, unix.NLM_F_ACK)
390 390
 
391 391
 	req.AddData(&nl.XfrmUsersaFlush{Proto: uint8(proto)})
392 392
 
393
-	_, err := req.Execute(syscall.NETLINK_XFRM, 0)
393
+	_, err := req.Execute(unix.NETLINK_XFRM, 0)
394 394
 	if err != nil {
395 395
 		return err
396 396
 	}
... ...
@@ -429,6 +432,16 @@ func lftToLimits(lft *nl.XfrmLifetimeCfg, lmts *XfrmStateLimits) {
429 429
 	*lmts = *(*XfrmStateLimits)(unsafe.Pointer(lft))
430 430
 }
431 431
 
432
+func curToStats(cur *nl.XfrmLifetimeCur, wstats *nl.XfrmStats, stats *XfrmStateStats) {
433
+	stats.Bytes = cur.Bytes
434
+	stats.Packets = cur.Packets
435
+	stats.AddTime = cur.AddTime
436
+	stats.UseTime = cur.UseTime
437
+	stats.ReplayWindow = wstats.ReplayWindow
438
+	stats.Replay = wstats.Replay
439
+	stats.Failed = wstats.IntegrityFailed
440
+}
441
+
432 442
 func xfrmUsersaInfoFromXfrmState(state *XfrmState) *nl.XfrmUsersaInfo {
433 443
 	msg := &nl.XfrmUsersaInfo{}
434 444
 	msg.Family = uint16(nl.GetIPFamily(state.Dst))
... ...
@@ -20,9 +20,10 @@ Testing (requires root):
20 20
 package main
21 21
 
22 22
 import (
23
+    "fmt"
23 24
     "net"
24 25
     "runtime"
25
-    "github.com/vishvananada/netns"
26
+    "github.com/vishvananda/netns"
26 27
 )
27 28
 
28 29
 func main() {
... ...
@@ -36,9 +37,10 @@ func main() {
36 36
 
37 37
     // Create a new network namespace
38 38
     newns, _ := netns.New()
39
+    netns.Set(newns)
39 40
     defer newns.Close()
40 41
 
41
-    // Do something with tne network namespace
42
+    // Do something with the network namespace
42 43
     ifaces, _ := net.Interfaces()
43 44
     fmt.Printf("Interfaces: %v\n", ifaces)
44 45
 
... ...
@@ -19,7 +19,7 @@ type NsHandle int
19 19
 
20 20
 // Equal determines if two network handles refer to the same network
21 21
 // namespace. This is done by comparing the device and inode that the
22
-// file descripors point to.
22
+// file descriptors point to.
23 23
 func (ns NsHandle) Equal(other NsHandle) bool {
24 24
 	if ns == other {
25 25
 		return true
... ...
@@ -46,6 +46,19 @@ func (ns NsHandle) String() string {
46 46
 	return fmt.Sprintf("NS(%d: %d, %d)", ns, s.Dev, s.Ino)
47 47
 }
48 48
 
49
+// UniqueId returns a string which uniquely identifies the namespace
50
+// associated with the network handle.
51
+func (ns NsHandle) UniqueId() string {
52
+	var s syscall.Stat_t
53
+	if ns == -1 {
54
+		return "NS(none)"
55
+	}
56
+	if err := syscall.Fstat(int(ns), &s); err != nil {
57
+		return "NS(unknown)"
58
+	}
59
+	return fmt.Sprintf("NS(%d:%d)", s.Dev, s.Ino)
60
+}
61
+
49 62
 // IsOpen returns true if Close() has not been called.
50 63
 func (ns NsHandle) IsOpen() bool {
51 64
 	return ns != -1
... ...
@@ -61,7 +74,7 @@ func (ns *NsHandle) Close() error {
61 61
 	return nil
62 62
 }
63 63
 
64
-// Get an empty (closed) NsHandle
64
+// None gets an empty (closed) NsHandle.
65 65
 func None() NsHandle {
66 66
 	return NsHandle(-1)
67 67
 }
... ...
@@ -7,14 +7,27 @@ import (
7 7
 	"io/ioutil"
8 8
 	"os"
9 9
 	"path/filepath"
10
+	"runtime"
10 11
 	"strconv"
11 12
 	"strings"
12 13
 	"syscall"
13 14
 )
14 15
 
16
+// SYS_SETNS syscall allows changing the namespace of the current process.
17
+var SYS_SETNS = map[string]uintptr{
18
+	"386":     346,
19
+	"amd64":   308,
20
+	"arm64":   268,
21
+	"arm":     375,
22
+	"mips":    4344,
23
+	"mipsle":  4344,
24
+	"ppc64":   350,
25
+	"ppc64le": 350,
26
+	"s390x":   339,
27
+}[runtime.GOARCH]
28
+
29
+// Deprecated: use syscall pkg instead (go >= 1.5 needed).
15 30
 const (
16
-	// These constants belong in the syscall library but have not been
17
-	// added yet.
18 31
 	CLONE_NEWUTS  = 0x04000000 /* New utsname group? */
19 32
 	CLONE_NEWIPC  = 0x08000000 /* New ipcs */
20 33
 	CLONE_NEWUSER = 0x10000000 /* New user namespace */
... ...
@@ -125,7 +138,9 @@ func getThisCgroup(cgroupType string) (string, error) {
125 125
 		return "", fmt.Errorf("docker pid not found in /var/run/docker.pid")
126 126
 	}
127 127
 	pid, err := strconv.Atoi(result[0])
128
-
128
+	if err != nil {
129
+		return "", err
130
+	}
129 131
 	output, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cgroup", pid))
130 132
 	if err != nil {
131 133
 		return "", err
... ...
@@ -167,8 +182,18 @@ func getPidForContainer(id string) (int, error) {
167 167
 		filepath.Join(cgroupRoot, cgroupThis, id, "tasks"),
168 168
 		// With more recent lxc versions use, cgroup will be in lxc/
169 169
 		filepath.Join(cgroupRoot, cgroupThis, "lxc", id, "tasks"),
170
-		// With more recent dockee, cgroup will be in docker/
170
+		// With more recent docker, cgroup will be in docker/
171 171
 		filepath.Join(cgroupRoot, cgroupThis, "docker", id, "tasks"),
172
+		// Even more recent docker versions under systemd use docker-<id>.scope/
173
+		filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", "tasks"),
174
+		// Even more recent docker versions under cgroup/systemd/docker/<id>/
175
+		filepath.Join(cgroupRoot, "..", "systemd", "docker", id, "tasks"),
176
+		// Kubernetes with docker and CNI is even more different
177
+		filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "*", "pod*", id, "tasks"),
178
+		// Another flavor of containers location in recent kubernetes 1.11+
179
+		filepath.Join(cgroupRoot, cgroupThis, "kubepods.slice", "kubepods-besteffort.slice", "*", "docker-"+id+".scope", "tasks"),
180
+		// When runs inside of a container with recent kubernetes 1.11+
181
+		filepath.Join(cgroupRoot, "kubepods.slice", "kubepods-besteffort.slice", "*", "docker-"+id+".scope", "tasks"),
172 182
 	}
173 183
 
174 184
 	var filename string
175 185
deleted file mode 100644
... ...
@@ -1,7 +0,0 @@
1
-// +build linux,386
2
-
3
-package netns
4
-
5
-const (
6
-	SYS_SETNS = 346
7
-)
8 1
deleted file mode 100644
... ...
@@ -1,7 +0,0 @@
1
-// +build linux,amd64
2
-
3
-package netns
4
-
5
-const (
6
-	SYS_SETNS = 308
7
-)
8 1
deleted file mode 100644
... ...
@@ -1,7 +0,0 @@
1
-// +build linux,arm
2
-
3
-package netns
4
-
5
-const (
6
-	SYS_SETNS = 375
7
-)
8 1
deleted file mode 100644
... ...
@@ -1,7 +0,0 @@
1
-// +build linux,arm64
2
-
3
-package netns
4
-
5
-const (
6
-	SYS_SETNS = 268
7
-)
8 1
deleted file mode 100644
... ...
@@ -1,7 +0,0 @@
1
-// +build linux,ppc64le
2
-
3
-package netns
4
-
5
-const (
6
-	SYS_SETNS = 350
7
-)
8 1
deleted file mode 100644
... ...
@@ -1,7 +0,0 @@
1
-// +build linux,s390x
2
-
3
-package netns
4
-
5
-const (
6
-	SYS_SETNS = 339
7
-)
... ...
@@ -22,6 +22,10 @@ func Get() (NsHandle, error) {
22 22
 	return -1, ErrNotImplemented
23 23
 }
24 24
 
25
+func GetFromPath(path string) (NsHandle, error) {
26
+	return -1, ErrNotImplemented
27
+}
28
+
25 29
 func GetFromName(name string) (NsHandle, error) {
26 30
 	return -1, ErrNotImplemented
27 31
 }
... ...
@@ -30,6 +34,10 @@ func GetFromPid(pid int) (NsHandle, error) {
30 30
 	return -1, ErrNotImplemented
31 31
 }
32 32
 
33
+func GetFromThread(pid, tid int) (NsHandle, error) {
34
+	return -1, ErrNotImplemented
35
+}
36
+
33 37
 func GetFromDocker(id string) (NsHandle, error) {
34 38
 	return -1, ErrNotImplemented
35 39
 }