Bläddra i källkod

Merge pull request #40683 from thaJeztah/bump_libnetwork

vendor: vishvananda/netlink v1.1.0
Brian Goff 5 år sedan
förälder
incheckning
30d54e64f6
61 ändrade filer med 3529 tillägg och 477 borttagningar
  1. 1 1
      hack/dockerfile/install/proxy.installer
  2. 4 3
      vendor.conf
  3. 1 1
      vendor/github.com/docker/libnetwork/drivers/overlay/ov_network.go
  4. 1 1
      vendor/github.com/docker/libnetwork/service_linux.go
  5. 4 2
      vendor/github.com/docker/libnetwork/vendor.conf
  6. 202 0
      vendor/github.com/moby/ipvs/LICENSE
  7. 34 0
      vendor/github.com/moby/ipvs/README.md
  8. 0 0
      vendor/github.com/moby/ipvs/constants.go
  9. 1 0
      vendor/github.com/moby/ipvs/doc.go
  10. 12 0
      vendor/github.com/moby/ipvs/go.mod
  11. 0 0
      vendor/github.com/moby/ipvs/ipvs.go
  12. 1 1
      vendor/github.com/moby/ipvs/netlink.go
  13. 84 21
      vendor/github.com/vishvananda/netlink/addr_linux.go
  14. 3 6
      vendor/github.com/vishvananda/netlink/bridge_linux.go
  15. 137 4
      vendor/github.com/vishvananda/netlink/class.go
  16. 137 8
      vendor/github.com/vishvananda/netlink/class_linux.go
  17. 71 48
      vendor/github.com/vishvananda/netlink/conntrack_linux.go
  18. 272 0
      vendor/github.com/vishvananda/netlink/devlink_linux.go
  19. 73 37
      vendor/github.com/vishvananda/netlink/filter.go
  20. 204 36
      vendor/github.com/vishvananda/netlink/filter_linux.go
  21. 1 5
      vendor/github.com/vishvananda/netlink/fou_linux.go
  22. 3 0
      vendor/github.com/vishvananda/netlink/genetlink_linux.go
  23. 8 0
      vendor/github.com/vishvananda/netlink/go.mod
  24. 1 1
      vendor/github.com/vishvananda/netlink/handle_linux.go
  25. 12 0
      vendor/github.com/vishvananda/netlink/handle_unspecified.go
  26. 1 9
      vendor/github.com/vishvananda/netlink/ioctl_linux.go
  27. 230 12
      vendor/github.com/vishvananda/netlink/link.go
  28. 468 115
      vendor/github.com/vishvananda/netlink/link_linux.go
  29. 7 0
      vendor/github.com/vishvananda/netlink/neigh.go
  30. 161 28
      vendor/github.com/vishvananda/netlink/neigh_linux.go
  31. 2 1
      vendor/github.com/vishvananda/netlink/netlink.go
  32. 12 0
      vendor/github.com/vishvananda/netlink/netlink_unspecified.go
  33. 141 0
      vendor/github.com/vishvananda/netlink/netns_linux.go
  34. 19 0
      vendor/github.com/vishvananda/netlink/netns_unspecified.go
  35. 2 2
      vendor/github.com/vishvananda/netlink/nl/bridge_linux.go
  36. 34 6
      vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go
  37. 40 0
      vendor/github.com/vishvananda/netlink/nl/devlink_linux.go
  38. 67 5
      vendor/github.com/vishvananda/netlink/nl/link_linux.go
  39. 44 22
      vendor/github.com/vishvananda/netlink/nl/nl_linux.go
  40. 35 0
      vendor/github.com/vishvananda/netlink/nl/rdma_link_linux.go
  41. 26 0
      vendor/github.com/vishvananda/netlink/nl/route_linux.go
  42. 43 0
      vendor/github.com/vishvananda/netlink/nl/seg6_linux.go
  43. 76 0
      vendor/github.com/vishvananda/netlink/nl/seg6local_linux.go
  44. 1 10
      vendor/github.com/vishvananda/netlink/nl/syscall.go
  45. 165 1
      vendor/github.com/vishvananda/netlink/nl/tc_linux.go
  46. 36 26
      vendor/github.com/vishvananda/netlink/nl/xfrm_linux.go
  47. 4 0
      vendor/github.com/vishvananda/netlink/protinfo.go
  48. 3 4
      vendor/github.com/vishvananda/netlink/protinfo_linux.go
  49. 48 0
      vendor/github.com/vishvananda/netlink/qdisc.go
  50. 45 24
      vendor/github.com/vishvananda/netlink/qdisc_linux.go
  51. 264 0
      vendor/github.com/vishvananda/netlink/rdma_link_linux.go
  52. 2 0
      vendor/github.com/vishvananda/netlink/route.go
  53. 216 13
      vendor/github.com/vishvananda/netlink/route_linux.go
  54. 1 1
      vendor/github.com/vishvananda/netlink/rule_linux.go
  55. 4 1
      vendor/github.com/vishvananda/netlink/socket_linux.go
  56. 5 1
      vendor/github.com/vishvananda/netlink/xfrm_monitor_linux.go
  57. 24 2
      vendor/github.com/vishvananda/netlink/xfrm_policy.go
  58. 13 6
      vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go
  59. 4 2
      vendor/github.com/vishvananda/netlink/xfrm_state.go
  60. 16 11
      vendor/github.com/vishvananda/netlink/xfrm_state_linux.go
  61. 3 0
      vendor/github.com/vishvananda/netns/go.mod

+ 1 - 1
hack/dockerfile/install/proxy.installer

@@ -3,7 +3,7 @@
 # LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When
 # updating the binary version, consider updating github.com/docker/libnetwork
 # in vendor.conf accordingly
-: "${LIBNETWORK_COMMIT:=bf2bd42abc0a3734f12b5ec724e571434e42c669}"
+: "${LIBNETWORK_COMMIT:=beab24292cb13d13670985fc860215f9e296bd47}"
 
 install_proxy() {
 	case "$1" in

+ 4 - 3
vendor.conf

@@ -38,7 +38,7 @@ github.com/gofrs/flock                              392e7fae8f1b0bdbd67dad7237d2
 # libnetwork
 
 # When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy.installer accordingly
-github.com/docker/libnetwork                        bf2bd42abc0a3734f12b5ec724e571434e42c669
+github.com/docker/libnetwork                        beab24292cb13d13670985fc860215f9e296bd47
 github.com/docker/go-events                         9461782956ad83b30282bf90e31fa6a70c255ba9
 github.com/armon/go-radix                           e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
 github.com/armon/go-metrics                         eb0af217e5e9747e41dd5303755356b62d28e3ec
@@ -50,8 +50,9 @@ github.com/hashicorp/go-sockaddr                    c7188e74f6acae5a989bdc959aa7
 github.com/hashicorp/go-multierror                  886a7fbe3eb1c874d46f623bfa70af45f425b3d1 # v1.0.0
 github.com/hashicorp/serf                           598c54895cc5a7b1a24a398d635e8c0ea0959870
 github.com/docker/libkv                             458977154600b9f23984d9f4b82e79570b5ae12b
-github.com/vishvananda/netns                        7109fa855b0ff1ebef7fbd2f6aa613e8db7cfbc0
-github.com/vishvananda/netlink                      a2ad57a690f3caf3015351d2d6e1c0b95c349752
+github.com/vishvananda/netns                        0a2b9b5464df8343199164a0321edf3313202f7e
+github.com/vishvananda/netlink                      f049be6f391489d3f374498fe0c8df8449258372 # v1.1.0
+github.com/moby/ipvs                                8f137da6850a975020f4f739c589d293dd3a9d7b # v1.0.0
 
 # When updating, consider updating TOMLV_COMMIT in hack/dockerfile/install/tomlv.installer accordingly
 github.com/BurntSushi/toml                          3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005 # v0.3.1

+ 1 - 1
vendor/github.com/docker/libnetwork/drivers/overlay/ov_network.go

@@ -793,7 +793,7 @@ func (n *network) watchMiss(nlSock *nl.NetlinkSocket, nsPath string) {
 		return
 	}
 	for {
-		msgs, err := nlSock.Receive()
+		msgs, _, err := nlSock.Receive()
 		if err != nil {
 			n.Lock()
 			nlFd := nlSock.GetFd()

+ 1 - 1
vendor/github.com/docker/libnetwork/service_linux.go

@@ -16,10 +16,10 @@ import (
 
 	"github.com/docker/docker/pkg/reexec"
 	"github.com/docker/libnetwork/iptables"
-	"github.com/docker/libnetwork/ipvs"
 	"github.com/docker/libnetwork/ns"
 	"github.com/gogo/protobuf/proto"
 	"github.com/ishidawataru/sctp"
+	"github.com/moby/ipvs"
 	"github.com/sirupsen/logrus"
 	"github.com/vishvananda/netlink/nl"
 	"github.com/vishvananda/netns"

+ 4 - 2
vendor/github.com/docker/libnetwork/vendor.conf

@@ -45,8 +45,8 @@ github.com/sirupsen/logrus              8bdbc7bcc01dcbb8ec23dc8a28e332258d25251f
 github.com/konsorten/go-windows-terminal-sequences   5c8c8bd35d3832f5d134ae1e1e375b69a4d25242 # v1.0.1
 github.com/ugorji/go                    b4c50a2b199d93b13dc15e78929cfb23bfdf21ab # v1.1.1
 github.com/urfave/cli                   a65b733b303f0055f8d324d805f393cd3e7a7904
-github.com/vishvananda/netlink          a2ad57a690f3caf3015351d2d6e1c0b95c349752 # v1.0.0
-github.com/vishvananda/netns            7109fa855b0ff1ebef7fbd2f6aa613e8db7cfbc0
+github.com/vishvananda/netlink          f049be6f391489d3f374498fe0c8df8449258372 # v1.1.0
+github.com/vishvananda/netns            0a2b9b5464df8343199164a0321edf3313202f7e
 golang.org/x/crypto                     b7391e95e576cacdcdd422573063bc057239113d
 golang.org/x/net                        a680a1efc54dd51c040b3b5ce4939ea3cf2ea0d1
 golang.org/x/sys                        d455e41777fca6e8a5a79e34a14b8368bc11d9ba
@@ -57,3 +57,5 @@ go.opencensus.io                        9c377598961b706d1542bd2d84d538b5094d596e
 
 gotest.tools                            1083505acf35a0bd8a696b26837e1fb3187a7a83 # v2.3.0
 github.com/google/go-cmp                3af367b6b30c263d47e8895973edcca9a49cf029 # v0.2.0
+
+github.com/moby/ipvs                    8f137da6850a975020f4f739c589d293dd3a9d7b # v1.0.0

+ 202 - 0
vendor/github.com/moby/ipvs/LICENSE

@@ -0,0 +1,202 @@
+Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+

+ 34 - 0
vendor/github.com/moby/ipvs/README.md

@@ -0,0 +1,34 @@
+# ipvs - networking for containers
+
+![Test](https://github.com/moby/ipvs/workflows/Test/badge.svg) [![GoDoc](https://godoc.org/github.com/moby/ipvs?status.svg)](https://godoc.org/github.com/moby/ipvs) [![Go Report Card](https://goreportcard.com/badge/github.com/moby/ipvs)](https://goreportcard.com/report/github.com/moby/ipvs)
+
+ipvs provides a native Go implementation for communicating with IPVS kernel module using a netlink socket.
+
+
+#### Using ipvs
+
+```go
+import (
+	"log"
+
+	"github.com/moby/ipvs"
+)
+
+func main() {
+	handle, err := ipvs.New("")
+	if err != nil {
+		log.Fatalf("ipvs.New: %s", err)
+	}
+	svcs, err := handle.GetServices()
+	if err != nil {
+		log.Fatalf("handle.GetServices: %s", err)
+	}
+}
+```
+
+## Contributing
+
+Want to hack on ipvs? [Docker's contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md) apply.
+
+## Copyright and license
+Code and documentation copyright 2015 Docker, inc. Code released under the Apache 2.0 license. Docs released under Creative commons.

+ 0 - 0
vendor/github.com/docker/libnetwork/ipvs/constants.go → vendor/github.com/moby/ipvs/constants.go


+ 1 - 0
vendor/github.com/moby/ipvs/doc.go

@@ -0,0 +1 @@
+package ipvs

+ 12 - 0
vendor/github.com/moby/ipvs/go.mod

@@ -0,0 +1,12 @@
+module github.com/moby/ipvs
+
+go 1.13
+
+require (
+	github.com/pkg/errors v0.9.1 // indirect
+	github.com/sirupsen/logrus v1.4.2
+	github.com/vishvananda/netlink v1.1.0
+	github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df
+	golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527
+	gotest.tools/v3 v3.0.2
+)

+ 0 - 0
vendor/github.com/docker/libnetwork/ipvs/ipvs.go → vendor/github.com/moby/ipvs/ipvs.go


+ 1 - 1
vendor/github.com/docker/libnetwork/ipvs/netlink.go → vendor/github.com/moby/ipvs/netlink.go

@@ -217,7 +217,7 @@ func execute(s *nl.NetlinkSocket, req *nl.NetlinkRequest, resType uint16) ([][]b
 
 done:
 	for {
-		msgs, err := s.Receive()
+		msgs, _, err := s.Receive()
 		if err != nil {
 			if s.GetFd() == -1 {
 				return nil, fmt.Errorf("Socket got closed on receive")

+ 84 - 21
vendor/github.com/vishvananda/netlink/addr_linux.go

@@ -15,39 +15,62 @@ import (
 const IFA_FLAGS = 0x8
 
 // AddrAdd will add an IP address to a link device.
+//
 // Equivalent to: `ip addr add $addr dev $link`
+//
+// If `addr` is an IPv4 address and the broadcast address is not given, it
+// will be automatically computed based on the IP mask if /30 or larger.
 func AddrAdd(link Link, addr *Addr) error {
 	return pkgHandle.AddrAdd(link, addr)
 }
 
 // AddrAdd will add an IP address to a link device.
+//
 // Equivalent to: `ip addr add $addr dev $link`
+//
+// If `addr` is an IPv4 address and the broadcast address is not given, it
+// will be automatically computed based on the IP mask if /30 or larger.
 func (h *Handle) AddrAdd(link Link, addr *Addr) error {
 	req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
 	return h.addrHandle(link, addr, req)
 }
 
 // AddrReplace will replace (or, if not present, add) an IP address on a link device.
+//
 // Equivalent to: `ip addr replace $addr dev $link`
+//
+// If `addr` is an IPv4 address and the broadcast address is not given, it
+// will be automatically computed based on the IP mask if /30 or larger.
 func AddrReplace(link Link, addr *Addr) error {
 	return pkgHandle.AddrReplace(link, addr)
 }
 
 // AddrReplace will replace (or, if not present, add) an IP address on a link device.
+//
 // Equivalent to: `ip addr replace $addr dev $link`
+//
+// If `addr` is an IPv4 address and the broadcast address is not given, it
+// will be automatically computed based on the IP mask if /30 or larger.
 func (h *Handle) AddrReplace(link Link, addr *Addr) error {
 	req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_REPLACE|unix.NLM_F_ACK)
 	return h.addrHandle(link, addr, req)
 }
 
 // AddrDel will delete an IP address from a link device.
+//
 // Equivalent to: `ip addr del $addr dev $link`
+//
+// If `addr` is an IPv4 address and the broadcast address is not given, it
+// will be automatically computed based on the IP mask if /30 or larger.
 func AddrDel(link Link, addr *Addr) error {
 	return pkgHandle.AddrDel(link, addr)
 }
 
 // AddrDel will delete an IP address from a link device.
 // Equivalent to: `ip addr del $addr dev $link`
+//
+// If `addr` is an IPv4 address and the broadcast address is not given, it
+// will be automatically computed based on the IP mask if /30 or larger.
 func (h *Handle) AddrDel(link Link, addr *Addr) error {
 	req := h.newNetlinkRequest(unix.RTM_DELADDR, unix.NLM_F_ACK)
 	return h.addrHandle(link, addr, req)
@@ -65,7 +88,11 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
 	msg := nl.NewIfAddrmsg(family)
 	msg.Index = uint32(base.Index)
 	msg.Scope = uint8(addr.Scope)
-	prefixlen, masklen := addr.Mask.Size()
+	mask := addr.Mask
+	if addr.Peer != nil {
+		mask = addr.Peer.Mask
+	}
+	prefixlen, masklen := mask.Size()
 	msg.Prefixlen = uint8(prefixlen)
 	req.AddData(msg)
 
@@ -104,14 +131,20 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
 	}
 
 	if family == FAMILY_V4 {
-		if addr.Broadcast == nil {
+		// Automatically set the broadcast address if it is unset and the
+		// subnet is large enough to sensibly have one (/30 or larger).
+		// See: RFC 3021
+		if addr.Broadcast == nil && prefixlen < 31 {
 			calcBroadcast := make(net.IP, masklen/8)
 			for i := range localAddrData {
-				calcBroadcast[i] = localAddrData[i] | ^addr.Mask[i]
+				calcBroadcast[i] = localAddrData[i] | ^mask[i]
 			}
 			addr.Broadcast = calcBroadcast
 		}
-		req.AddData(nl.NewRtAttr(unix.IFA_BROADCAST, addr.Broadcast))
+
+		if addr.Broadcast != nil {
+			req.AddData(nl.NewRtAttr(unix.IFA_BROADCAST, addr.Broadcast))
+		}
 
 		if addr.Label != "" {
 			labelData := nl.NewRtAttr(unix.IFA_LABEL, nl.ZeroTerminated(addr.Label))
@@ -206,13 +239,17 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
 				IP:   attr.Value,
 				Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
 			}
-			addr.Peer = dst
 		case unix.IFA_LOCAL:
+			// iproute2 manual:
+			// If a peer address is specified, the local address
+			// cannot have a prefix length. The network prefix is
+			// associated with the peer rather than with the local
+			// address.
+			n := 8 * len(attr.Value)
 			local = &net.IPNet{
 				IP:   attr.Value,
-				Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
+				Mask: net.CIDRMask(n, n),
 			}
-			addr.IPNet = local
 		case unix.IFA_BROADCAST:
 			addr.Broadcast = attr.Value
 		case unix.IFA_LABEL:
@@ -226,12 +263,24 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
 		}
 	}
 
-	// IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
+	// libnl addr.c comment:
+	// IPv6 sends the local address as IFA_ADDRESS with no
+	// IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS
+	// with IFA_ADDRESS being the peer address if they differ
+	//
+	// But obviously, as there are IPv6 PtP addresses, too,
+	// IFA_LOCAL should also be handled for IPv6.
 	if local != nil {
-		addr.IPNet = local
+		if family == FAMILY_V4 && local.IP.Equal(dst.IP) {
+			addr.IPNet = dst
+		} else {
+			addr.IPNet = local
+			addr.Peer = dst
+		}
 	} else {
 		addr.IPNet = dst
 	}
+
 	addr.Scope = int(msg.Scope)
 
 	return
@@ -250,21 +299,22 @@ type AddrUpdate struct {
 // AddrSubscribe takes a chan down which notifications will be sent
 // when addresses change.  Close the 'done' chan to stop subscription.
 func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
-	return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
+	return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0)
 }
 
 // AddrSubscribeAt works like AddrSubscribe plus it allows the caller
 // to choose the network namespace in which to subscribe (ns).
 func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
-	return addrSubscribeAt(ns, netns.None(), ch, done, nil, false)
+	return addrSubscribeAt(ns, netns.None(), ch, done, nil, false, 0)
 }
 
 // AddrSubscribeOptions contains a set of options to use with
 // AddrSubscribeWithOptions.
 type AddrSubscribeOptions struct {
-	Namespace     *netns.NsHandle
-	ErrorCallback func(error)
-	ListExisting  bool
+	Namespace         *netns.NsHandle
+	ErrorCallback     func(error)
+	ListExisting      bool
+	ReceiveBufferSize int
 }
 
 // AddrSubscribeWithOptions work like AddrSubscribe but enable to
@@ -275,10 +325,10 @@ func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, option
 		none := netns.None()
 		options.Namespace = &none
 	}
-	return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
+	return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting, options.ReceiveBufferSize)
 }
 
-func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
+func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool, rcvbuf int) error {
 	s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_IFADDR, unix.RTNLGRP_IPV6_IFADDR)
 	if err != nil {
 		return err
@@ -289,6 +339,12 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
 			s.Close()
 		}()
 	}
+	if rcvbuf != 0 {
+		err = pkgHandle.SetSocketReceiveBufferSize(rcvbuf, false)
+		if err != nil {
+			return err
+		}
+	}
 	if listExisting {
 		req := pkgHandle.newNetlinkRequest(unix.RTM_GETADDR,
 			unix.NLM_F_DUMP)
@@ -301,13 +357,19 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
 	go func() {
 		defer close(ch)
 		for {
-			msgs, err := s.Receive()
+			msgs, from, err := s.Receive()
 			if err != nil {
 				if cberr != nil {
 					cberr(err)
 				}
 				return
 			}
+			if from.Pid != nl.PidKernel {
+				if cberr != nil {
+					cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel))
+				}
+				continue
+			}
 			for _, m := range msgs {
 				if m.Header.Type == unix.NLMSG_DONE {
 					continue
@@ -319,16 +381,17 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
 						continue
 					}
 					if cberr != nil {
-						cberr(syscall.Errno(-error))
+						cberr(fmt.Errorf("error message: %v",
+							syscall.Errno(-error)))
 					}
-					return
+					continue
 				}
 				msgType := m.Header.Type
 				if msgType != unix.RTM_NEWADDR && msgType != unix.RTM_DELADDR {
 					if cberr != nil {
 						cberr(fmt.Errorf("bad message type: %d", msgType))
 					}
-					return
+					continue
 				}
 
 				addr, _, ifindex, err := parseAddr(m.Data)
@@ -336,7 +399,7 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
 					if cberr != nil {
 						cberr(fmt.Errorf("could not parse address: %v", err))
 					}
-					return
+					continue
 				}
 
 				ch <- AddrUpdate{LinkAddress: *addr.IPNet,

+ 3 - 6
vendor/github.com/vishvananda/netlink/bridge_linux.go

@@ -96,7 +96,7 @@ func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged
 		flags |= nl.BRIDGE_FLAGS_MASTER
 	}
 	if flags > 0 {
-		nl.NewRtAttrChild(br, nl.IFLA_BRIDGE_FLAGS, nl.Uint16Attr(flags))
+		br.AddRtAttr(nl.IFLA_BRIDGE_FLAGS, nl.Uint16Attr(flags))
 	}
 	vlanInfo := &nl.BridgeVlanInfo{Vid: vid}
 	if pvid {
@@ -105,11 +105,8 @@ func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged
 	if untagged {
 		vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_UNTAGGED
 	}
-	nl.NewRtAttrChild(br, nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
+	br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
 	req.AddData(br)
 	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
-	if err != nil {
-		return err
-	}
-	return nil
+	return err
 }

+ 137 - 4
vendor/github.com/vishvananda/netlink/class.go

@@ -4,25 +4,76 @@ import (
 	"fmt"
 )
 
+// Class interfaces for all classes
 type Class interface {
 	Attrs() *ClassAttrs
 	Type() string
 }
 
+// Generic networking statistics for netlink users.
+// This file contains "gnet_" prefixed structs and relevant functions.
+// See Documentation/networking/getn_stats.txt in Linux source code for more details.
+
+// GnetStatsBasic Ref: struct gnet_stats_basic { ... }
+type GnetStatsBasic struct {
+	Bytes   uint64 // number of seen bytes
+	Packets uint32 // number of seen packets
+}
+
+// GnetStatsRateEst Ref: struct gnet_stats_rate_est { ... }
+type GnetStatsRateEst struct {
+	Bps uint32 // current byte rate
+	Pps uint32 // current packet rate
+}
+
+// GnetStatsRateEst64 Ref: struct gnet_stats_rate_est64 { ... }
+type GnetStatsRateEst64 struct {
+	Bps uint64 // current byte rate
+	Pps uint64 // current packet rate
+}
+
+// GnetStatsQueue Ref: struct gnet_stats_queue { ... }
+type GnetStatsQueue struct {
+	Qlen       uint32 // queue length
+	Backlog    uint32 // backlog size of queue
+	Drops      uint32 // number of dropped packets
+	Requeues   uint32 // number of requues
+	Overlimits uint32 // number of enqueues over the limit
+}
+
+// ClassStatistics representation based on generic networking statistics for netlink.
+// See Documentation/networking/gen_stats.txt in Linux source code for more details.
+type ClassStatistics struct {
+	Basic   *GnetStatsBasic
+	Queue   *GnetStatsQueue
+	RateEst *GnetStatsRateEst
+}
+
+// NewClassStatistics Construct a ClassStatistics struct which fields are all initialized by 0.
+func NewClassStatistics() *ClassStatistics {
+	return &ClassStatistics{
+		Basic:   &GnetStatsBasic{},
+		Queue:   &GnetStatsQueue{},
+		RateEst: &GnetStatsRateEst{},
+	}
+}
+
 // ClassAttrs represents a netlink class. A filter is associated with a link,
 // has a handle and a parent. The root filter of a device should have a
 // parent == HANDLE_ROOT.
 type ClassAttrs struct {
-	LinkIndex int
-	Handle    uint32
-	Parent    uint32
-	Leaf      uint32
+	LinkIndex  int
+	Handle     uint32
+	Parent     uint32
+	Leaf       uint32
+	Statistics *ClassStatistics
 }
 
 func (q ClassAttrs) String() string {
 	return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Leaf: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Leaf)
 }
 
+// HtbClassAttrs stores the attributes of HTB class
 type HtbClassAttrs struct {
 	// TODO handle all attributes
 	Rate    uint64
@@ -54,10 +105,12 @@ func (q HtbClass) String() string {
 	return fmt.Sprintf("{Rate: %d, Ceil: %d, Buffer: %d, Cbuffer: %d}", q.Rate, q.Ceil, q.Buffer, q.Cbuffer)
 }
 
+// Attrs returns the class attributes
 func (q *HtbClass) Attrs() *ClassAttrs {
 	return &q.ClassAttrs
 }
 
+// Type return the class type
 func (q *HtbClass) Type() string {
 	return "htb"
 }
@@ -69,10 +122,90 @@ type GenericClass struct {
 	ClassType string
 }
 
+// Attrs return the class attributes
 func (class *GenericClass) Attrs() *ClassAttrs {
 	return &class.ClassAttrs
 }
 
+// Type return the class type
 func (class *GenericClass) Type() string {
 	return class.ClassType
 }
+
+// ServiceCurve is the way the HFSC curve are represented
+type ServiceCurve struct {
+	m1 uint32
+	d  uint32
+	m2 uint32
+}
+
+// Attrs return the parameters of the service curve
+func (c *ServiceCurve) Attrs() (uint32, uint32, uint32) {
+	return c.m1, c.d, c.m2
+}
+
+// HfscClass is a representation of the HFSC class
+type HfscClass struct {
+	ClassAttrs
+	Rsc ServiceCurve
+	Fsc ServiceCurve
+	Usc ServiceCurve
+}
+
+// SetUsc sets the Usc curve
+func (hfsc *HfscClass) SetUsc(m1 uint32, d uint32, m2 uint32) {
+	hfsc.Usc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+}
+
+// SetFsc sets the Fsc curve
+func (hfsc *HfscClass) SetFsc(m1 uint32, d uint32, m2 uint32) {
+	hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+}
+
+// SetRsc sets the Rsc curve
+func (hfsc *HfscClass) SetRsc(m1 uint32, d uint32, m2 uint32) {
+	hfsc.Rsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+}
+
+// SetSC implements the SC from the tc CLI
+func (hfsc *HfscClass) SetSC(m1 uint32, d uint32, m2 uint32) {
+	hfsc.Rsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+	hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+}
+
+// SetUL implements the UL from the tc CLI
+func (hfsc *HfscClass) SetUL(m1 uint32, d uint32, m2 uint32) {
+	hfsc.Usc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+}
+
+// SetLS implements the LS from the tc CLI
+func (hfsc *HfscClass) SetLS(m1 uint32, d uint32, m2 uint32) {
+	hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+}
+
+// NewHfscClass returns a new HFSC struct with the set parameters
+func NewHfscClass(attrs ClassAttrs) *HfscClass {
+	return &HfscClass{
+		ClassAttrs: attrs,
+		Rsc:        ServiceCurve{},
+		Fsc:        ServiceCurve{},
+		Usc:        ServiceCurve{},
+	}
+}
+
+func (hfsc *HfscClass) String() string {
+	return fmt.Sprintf(
+		"{%s -- {RSC: {m1=%d d=%d m2=%d}} {FSC: {m1=%d d=%d m2=%d}} {USC: {m1=%d d=%d m2=%d}}}",
+		hfsc.Attrs(), hfsc.Rsc.m1*8, hfsc.Rsc.d, hfsc.Rsc.m2*8, hfsc.Fsc.m1*8, hfsc.Fsc.d, hfsc.Fsc.m2*8, hfsc.Usc.m1*8, hfsc.Usc.d, hfsc.Usc.m2*8,
+	)
+}
+
+// Attrs return the Hfsc parameters
+func (hfsc *HfscClass) Attrs() *ClassAttrs {
+	return &hfsc.ClassAttrs
+}
+
+// Type return the type of the class
+func (hfsc *HfscClass) Type() string {
+	return "hfsc"
+}

+ 137 - 8
vendor/github.com/vishvananda/netlink/class_linux.go

@@ -1,14 +1,34 @@
 package netlink
 
 import (
+	"bytes"
+	"encoding/binary"
+	"encoding/hex"
 	"errors"
+	"fmt"
 	"syscall"
 
 	"github.com/vishvananda/netlink/nl"
 	"golang.org/x/sys/unix"
 )
 
-// NOTE: function is in here because it uses other linux functions
+// Internal tc_stats representation in Go struct.
+// This is for internal uses only to deserialize the payload of rtattr.
+// After the deserialization, this should be converted into the canonical stats
+// struct, ClassStatistics, in case of statistics of a class.
+// Ref: struct tc_stats { ... }
+type tcStats struct {
+	Bytes      uint64 // Number of enqueued bytes
+	Packets    uint32 // Number of enqueued packets
+	Drops      uint32 // Packets dropped because of lack of resources
+	Overlimits uint32 // Number of throttle events when this flow goes out of allocated bandwidth
+	Bps        uint32 // Current flow byte rate
+	Pps        uint32 // Current flow packet rate
+	Qlen       uint32
+	Backlog    uint32
+}
+
+// NewHtbClass NOTE: function is in here because it uses other linux functions
 func NewHtbClass(attrs ClassAttrs, cattrs HtbClassAttrs) *HtbClass {
 	mtu := 1600
 	rate := cattrs.Rate / 8
@@ -126,7 +146,9 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
 	req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(class.Type())))
 
 	options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
-	if htb, ok := class.(*HtbClass); ok {
+	switch class.Type() {
+	case "htb":
+		htb := class.(*HtbClass)
 		opt := nl.TcHtbCopt{}
 		opt.Buffer = htb.Buffer
 		opt.Cbuffer = htb.Cbuffer
@@ -151,9 +173,18 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
 			return errors.New("HTB: failed to calculate ceil rate table")
 		}
 		opt.Ceil = tcceil
-		nl.NewRtAttrChild(options, nl.TCA_HTB_PARMS, opt.Serialize())
-		nl.NewRtAttrChild(options, nl.TCA_HTB_RTAB, SerializeRtab(rtab))
-		nl.NewRtAttrChild(options, nl.TCA_HTB_CTAB, SerializeRtab(ctab))
+		options.AddRtAttr(nl.TCA_HTB_PARMS, opt.Serialize())
+		options.AddRtAttr(nl.TCA_HTB_RTAB, SerializeRtab(rtab))
+		options.AddRtAttr(nl.TCA_HTB_CTAB, SerializeRtab(ctab))
+	case "hfsc":
+		hfsc := class.(*HfscClass)
+		opt := nl.HfscCopt{}
+		opt.Rsc.Set(hfsc.Rsc.Attrs())
+		opt.Fsc.Set(hfsc.Fsc.Attrs())
+		opt.Usc.Set(hfsc.Usc.Attrs())
+		options.AddRtAttr(nl.TCA_HFSC_RSC, nl.SerializeHfscCurve(&opt.Rsc))
+		options.AddRtAttr(nl.TCA_HFSC_FSC, nl.SerializeHfscCurve(&opt.Fsc))
+		options.AddRtAttr(nl.TCA_HFSC_USC, nl.SerializeHfscCurve(&opt.Usc))
 	}
 	req.AddData(options)
 	return nil
@@ -197,9 +228,10 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
 		}
 
 		base := ClassAttrs{
-			LinkIndex: int(msg.Ifindex),
-			Handle:    msg.Handle,
-			Parent:    msg.Parent,
+			LinkIndex:  int(msg.Ifindex),
+			Handle:     msg.Handle,
+			Parent:     msg.Parent,
+			Statistics: nil,
 		}
 
 		var class Class
@@ -211,6 +243,8 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
 				switch classType {
 				case "htb":
 					class = &HtbClass{}
+				case "hfsc":
+					class = &HfscClass{}
 				default:
 					class = &GenericClass{ClassType: classType}
 				}
@@ -225,6 +259,26 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
 					if err != nil {
 						return nil, err
 					}
+				case "hfsc":
+					data, err := nl.ParseRouteAttr(attr.Value)
+					if err != nil {
+						return nil, err
+					}
+					_, err = parseHfscClassData(class, data)
+					if err != nil {
+						return nil, err
+					}
+				}
+			// For backward compatibility.
+			case nl.TCA_STATS:
+				base.Statistics, err = parseTcStats(attr.Value)
+				if err != nil {
+					return nil, err
+				}
+			case nl.TCA_STATS2:
+				base.Statistics, err = parseTcStats2(attr.Value)
+				if err != nil {
+					return nil, err
 				}
 			}
 		}
@@ -253,3 +307,78 @@ func parseHtbClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, erro
 	}
 	return detailed, nil
 }
+
+func parseHfscClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, error) {
+	hfsc := class.(*HfscClass)
+	detailed := false
+	for _, datum := range data {
+		m1, d, m2 := nl.DeserializeHfscCurve(datum.Value).Attrs()
+		switch datum.Attr.Type {
+		case nl.TCA_HFSC_RSC:
+			hfsc.Rsc = ServiceCurve{m1: m1, d: d, m2: m2}
+		case nl.TCA_HFSC_FSC:
+			hfsc.Fsc = ServiceCurve{m1: m1, d: d, m2: m2}
+		case nl.TCA_HFSC_USC:
+			hfsc.Usc = ServiceCurve{m1: m1, d: d, m2: m2}
+		}
+	}
+	return detailed, nil
+}
+
+func parseTcStats(data []byte) (*ClassStatistics, error) {
+	buf := &bytes.Buffer{}
+	buf.Write(data)
+	native := nl.NativeEndian()
+	tcStats := &tcStats{}
+	if err := binary.Read(buf, native, tcStats); err != nil {
+		return nil, err
+	}
+
+	stats := NewClassStatistics()
+	stats.Basic.Bytes = tcStats.Bytes
+	stats.Basic.Packets = tcStats.Packets
+	stats.Queue.Qlen = tcStats.Qlen
+	stats.Queue.Backlog = tcStats.Backlog
+	stats.Queue.Drops = tcStats.Drops
+	stats.Queue.Overlimits = tcStats.Overlimits
+	stats.RateEst.Bps = tcStats.Bps
+	stats.RateEst.Pps = tcStats.Pps
+
+	return stats, nil
+}
+
+func parseGnetStats(data []byte, gnetStats interface{}) error {
+	buf := &bytes.Buffer{}
+	buf.Write(data)
+	native := nl.NativeEndian()
+	return binary.Read(buf, native, gnetStats)
+}
+
+func parseTcStats2(data []byte) (*ClassStatistics, error) {
+	rtAttrs, err := nl.ParseRouteAttr(data)
+	if err != nil {
+		return nil, err
+	}
+	stats := NewClassStatistics()
+	for _, datum := range rtAttrs {
+		switch datum.Attr.Type {
+		case nl.TCA_STATS_BASIC:
+			if err := parseGnetStats(datum.Value, stats.Basic); err != nil {
+				return nil, fmt.Errorf("Failed to parse ClassStatistics.Basic with: %v\n%s",
+					err, hex.Dump(datum.Value))
+			}
+		case nl.TCA_STATS_QUEUE:
+			if err := parseGnetStats(datum.Value, stats.Queue); err != nil {
+				return nil, fmt.Errorf("Failed to parse ClassStatistics.Queue with: %v\n%s",
+					err, hex.Dump(datum.Value))
+			}
+		case nl.TCA_STATS_RATE_EST:
+			if err := parseGnetStats(datum.Value, stats.RateEst); err != nil {
+				return nil, fmt.Errorf("Failed to parse ClassStatistics.RateEst with: %v\n%s",
+					err, hex.Dump(datum.Value))
+			}
+		}
+	}
+
+	return stats, nil
+}

+ 71 - 48
vendor/github.com/vishvananda/netlink/conntrack_linux.go

@@ -22,11 +22,7 @@ const (
 	// https://github.com/torvalds/linux/blob/master/include/uapi/linux/netfilter/nfnetlink.h -> #define NFNL_SUBSYS_CTNETLINK_EXP 2
 	ConntrackExpectTable = 2
 )
-const (
-	// For Parsing Mark
-	TCP_PROTO = 6
-	UDP_PROTO = 17
-)
+
 const (
 	// backward compatibility with golang 1.6 which does not have io.SeekCurrent
 	seekCurrent = 1
@@ -135,11 +131,13 @@ func (h *Handle) dumpConntrackTable(table ConntrackTableType, family InetFamily)
 // http://git.netfilter.org/libnetfilter_conntrack/tree/include/internal/object.h
 // For the time being, the structure below allows to parse and extract the base information of a flow
 type ipTuple struct {
-	SrcIP    net.IP
+	Bytes    uint64
 	DstIP    net.IP
+	DstPort  uint16
+	Packets  uint64
 	Protocol uint8
+	SrcIP    net.IP
 	SrcPort  uint16
-	DstPort  uint16
 }
 
 type ConntrackFlow struct {
@@ -151,11 +149,12 @@ type ConntrackFlow struct {
 
 func (s *ConntrackFlow) String() string {
 	// conntrack cmd output:
-	// udp      17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001 mark=0
-	return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d\tsrc=%s dst=%s sport=%d dport=%d mark=%d",
+	// udp      17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 packets=5 bytes=532 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001 packets=10 bytes=1078 mark=0
+	return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d packets=%d bytes=%d\tsrc=%s dst=%s sport=%d dport=%d packets=%d bytes=%d mark=%d",
 		nl.L4ProtoMap[s.Forward.Protocol], s.Forward.Protocol,
-		s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort,
-		s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort, s.Mark)
+		s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort, s.Forward.Packets, s.Forward.Bytes,
+		s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort, s.Reverse.Packets, s.Reverse.Bytes,
+		s.Mark)
 }
 
 // This method parse the ip tuple structure
@@ -220,9 +219,35 @@ func parseBERaw16(r *bytes.Reader, v *uint16) {
 	binary.Read(r, binary.BigEndian, v)
 }
 
+func parseBERaw32(r *bytes.Reader, v *uint32) {
+	binary.Read(r, binary.BigEndian, v)
+}
+
+func parseBERaw64(r *bytes.Reader, v *uint64) {
+	binary.Read(r, binary.BigEndian, v)
+}
+
+func parseByteAndPacketCounters(r *bytes.Reader) (bytes, packets uint64) {
+	for i := 0; i < 2; i++ {
+		switch _, t, _ := parseNfAttrTL(r); t {
+		case nl.CTA_COUNTERS_BYTES:
+			parseBERaw64(r, &bytes)
+		case nl.CTA_COUNTERS_PACKETS:
+			parseBERaw64(r, &packets)
+		default:
+			return
+		}
+	}
+	return
+}
+
+func parseConnectionMark(r *bytes.Reader) (mark uint32) {
+	parseBERaw32(r, &mark)
+	return
+}
+
 func parseRawData(data []byte) *ConntrackFlow {
 	s := &ConntrackFlow{}
-	var proto uint8
 	// First there is the Nfgenmsg header
 	// consume only the family field
 	reader := bytes.NewReader(data)
@@ -238,36 +263,31 @@ func parseRawData(data []byte) *ConntrackFlow {
 	// <len, NLA_F_NESTED|CTA_TUPLE_IP> 4 bytes
 	// flow information of the reverse flow
 	for reader.Len() > 0 {
-		nested, t, l := parseNfAttrTL(reader)
-		if nested && t == nl.CTA_TUPLE_ORIG {
-			if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
-				proto = parseIpTuple(reader, &s.Forward)
+		if nested, t, l := parseNfAttrTL(reader); nested {
+			switch t {
+			case nl.CTA_TUPLE_ORIG:
+				if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
+					parseIpTuple(reader, &s.Forward)
+				}
+			case nl.CTA_TUPLE_REPLY:
+				if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
+					parseIpTuple(reader, &s.Reverse)
+				} else {
+					// Header not recognized skip it
+					reader.Seek(int64(l), seekCurrent)
+				}
+			case nl.CTA_COUNTERS_ORIG:
+				s.Forward.Bytes, s.Forward.Packets = parseByteAndPacketCounters(reader)
+			case nl.CTA_COUNTERS_REPLY:
+				s.Reverse.Bytes, s.Reverse.Packets = parseByteAndPacketCounters(reader)
 			}
-		} else if nested && t == nl.CTA_TUPLE_REPLY {
-			if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
-				parseIpTuple(reader, &s.Reverse)
-
-				// Got all the useful information stop parsing
-				break
-			} else {
-				// Header not recognized skip it
-				reader.Seek(int64(l), seekCurrent)
+		} else {
+			switch t {
+			case nl.CTA_MARK:
+				s.Mark = parseConnectionMark(reader)
 			}
 		}
 	}
-	if proto == TCP_PROTO {
-		reader.Seek(64, seekCurrent)
-		_, t, _, v := parseNfAttrTLV(reader)
-		if t == nl.CTA_MARK {
-			s.Mark = uint32(v[3])
-		}
-	} else if proto == UDP_PROTO {
-		reader.Seek(16, seekCurrent)
-		_, t, _, v := parseNfAttrTLV(reader)
-		if t == nl.CTA_MARK {
-			s.Mark = uint32(v[3])
-		}
-	}
 	return s
 }
 
@@ -285,7 +305,7 @@ func parseRawData(data []byte) *ConntrackFlow {
 // Common parameters and options:
 //   -s, --src, --orig-src ip              Source address from original direction
 //   -d, --dst, --orig-dst ip              Destination address from original direction
-//   -r, --reply-src ip            Source addres from reply direction
+//   -r, --reply-src ip            Source address from reply direction
 //   -q, --reply-dst ip            Destination address from reply direction
 //   -p, --protonum proto          Layer 4 Protocol, eg. 'tcp'
 //   -f, --family proto            Layer 3 Protocol, eg. 'ipv6'
@@ -302,11 +322,14 @@ func parseRawData(data []byte) *ConntrackFlow {
 type ConntrackFilterType uint8
 
 const (
-	ConntrackOrigSrcIP = iota // -orig-src ip   Source address from original direction
-	ConntrackOrigDstIP        // -orig-dst ip   Destination address from original direction
-	ConntrackNatSrcIP         // -src-nat ip    Source NAT ip
-	ConntrackNatDstIP         // -dst-nat ip    Destination NAT ip
-	ConntrackNatAnyIP         // -any-nat ip    Source or destination NAT ip
+	ConntrackOrigSrcIP  = iota                // -orig-src ip    Source address from original direction
+	ConntrackOrigDstIP                        // -orig-dst ip    Destination address from original direction
+	ConntrackReplySrcIP                       // --reply-src ip  Reply Source IP
+	ConntrackReplyDstIP                       // --reply-dst ip  Reply Destination IP
+	ConntrackReplyAnyIP                       // Match source or destination reply IP
+	ConntrackNatSrcIP   = ConntrackReplySrcIP // deprecated use instead ConntrackReplySrcIP
+	ConntrackNatDstIP   = ConntrackReplyDstIP // deprecated use instead ConntrackReplyDstIP
+	ConntrackNatAnyIP   = ConntrackReplyAnyIP // deprecated use instaed ConntrackReplyAnyIP
 )
 
 type CustomConntrackFilter interface {
@@ -351,17 +374,17 @@ func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool {
 	}
 
 	// -src-nat ip    Source NAT ip
-	if elem, found := f.ipFilter[ConntrackNatSrcIP]; match && found {
+	if elem, found := f.ipFilter[ConntrackReplySrcIP]; match && found {
 		match = match && elem.Equal(flow.Reverse.SrcIP)
 	}
 
 	// -dst-nat ip    Destination NAT ip
-	if elem, found := f.ipFilter[ConntrackNatDstIP]; match && found {
+	if elem, found := f.ipFilter[ConntrackReplyDstIP]; match && found {
 		match = match && elem.Equal(flow.Reverse.DstIP)
 	}
 
-	// -any-nat ip    Source or destination NAT ip
-	if elem, found := f.ipFilter[ConntrackNatAnyIP]; match && found {
+	// Match source or destination reply IP
+	if elem, found := f.ipFilter[ConntrackReplyAnyIP]; match && found {
 		match = match && (elem.Equal(flow.Reverse.SrcIP) || elem.Equal(flow.Reverse.DstIP))
 	}
 

+ 272 - 0
vendor/github.com/vishvananda/netlink/devlink_linux.go

@@ -0,0 +1,272 @@
+package netlink
+
+import (
+	"syscall"
+
+	"fmt"
+	"github.com/vishvananda/netlink/nl"
+	"golang.org/x/sys/unix"
+)
+
+// DevlinkDevEswitchAttr represents device's eswitch attributes
+type DevlinkDevEswitchAttr struct {
+	Mode       string
+	InlineMode string
+	EncapMode  string
+}
+
+// DevlinkDevAttrs represents device attributes
+type DevlinkDevAttrs struct {
+	Eswitch DevlinkDevEswitchAttr
+}
+
+// DevlinkDevice represents device and its attributes
+type DevlinkDevice struct {
+	BusName    string
+	DeviceName string
+	Attrs      DevlinkDevAttrs
+}
+
+func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) {
+	devices := make([]*DevlinkDevice, 0, len(msgs))
+	for _, m := range msgs {
+		attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
+		if err != nil {
+			return nil, err
+		}
+		dev := &DevlinkDevice{}
+		if err = dev.parseAttributes(attrs); err != nil {
+			return nil, err
+		}
+		devices = append(devices, dev)
+	}
+	return devices, nil
+}
+
+func eswitchStringToMode(modeName string) (uint16, error) {
+	if modeName == "legacy" {
+		return nl.DEVLINK_ESWITCH_MODE_LEGACY, nil
+	} else if modeName == "switchdev" {
+		return nl.DEVLINK_ESWITCH_MODE_SWITCHDEV, nil
+	} else {
+		return 0xffff, fmt.Errorf("invalid switchdev mode")
+	}
+}
+
+func parseEswitchMode(mode uint16) string {
+	var eswitchMode = map[uint16]string{
+		nl.DEVLINK_ESWITCH_MODE_LEGACY:    "legacy",
+		nl.DEVLINK_ESWITCH_MODE_SWITCHDEV: "switchdev",
+	}
+	if eswitchMode[mode] == "" {
+		return "unknown"
+	} else {
+		return eswitchMode[mode]
+	}
+}
+
+func parseEswitchInlineMode(inlinemode uint8) string {
+	var eswitchInlineMode = map[uint8]string{
+		nl.DEVLINK_ESWITCH_INLINE_MODE_NONE:      "none",
+		nl.DEVLINK_ESWITCH_INLINE_MODE_LINK:      "link",
+		nl.DEVLINK_ESWITCH_INLINE_MODE_NETWORK:   "network",
+		nl.DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT: "transport",
+	}
+	if eswitchInlineMode[inlinemode] == "" {
+		return "unknown"
+	} else {
+		return eswitchInlineMode[inlinemode]
+	}
+}
+
+func parseEswitchEncapMode(encapmode uint8) string {
+	var eswitchEncapMode = map[uint8]string{
+		nl.DEVLINK_ESWITCH_ENCAP_MODE_NONE:  "disable",
+		nl.DEVLINK_ESWITCH_ENCAP_MODE_BASIC: "enable",
+	}
+	if eswitchEncapMode[encapmode] == "" {
+		return "unknown"
+	} else {
+		return eswitchEncapMode[encapmode]
+	}
+}
+
+func (d *DevlinkDevice) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
+	for _, a := range attrs {
+		switch a.Attr.Type {
+		case nl.DEVLINK_ATTR_BUS_NAME:
+			d.BusName = string(a.Value)
+		case nl.DEVLINK_ATTR_DEV_NAME:
+			d.DeviceName = string(a.Value)
+		case nl.DEVLINK_ATTR_ESWITCH_MODE:
+			d.Attrs.Eswitch.Mode = parseEswitchMode(native.Uint16(a.Value))
+		case nl.DEVLINK_ATTR_ESWITCH_INLINE_MODE:
+			d.Attrs.Eswitch.InlineMode = parseEswitchInlineMode(uint8(a.Value[0]))
+		case nl.DEVLINK_ATTR_ESWITCH_ENCAP_MODE:
+			d.Attrs.Eswitch.EncapMode = parseEswitchEncapMode(uint8(a.Value[0]))
+		}
+	}
+	return nil
+}
+
+func (dev *DevlinkDevice) parseEswitchAttrs(msgs [][]byte) {
+	m := msgs[0]
+	attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
+	if err != nil {
+		return
+	}
+	dev.parseAttributes(attrs)
+}
+
+func (h *Handle) getEswitchAttrs(family *GenlFamily, dev *DevlinkDevice) {
+	msg := &nl.Genlmsg{
+		Command: nl.DEVLINK_CMD_ESWITCH_GET,
+		Version: nl.GENL_DEVLINK_VERSION,
+	}
+	req := h.newNetlinkRequest(int(family.ID), unix.NLM_F_REQUEST|unix.NLM_F_ACK)
+	req.AddData(msg)
+
+	b := make([]byte, len(dev.BusName))
+	copy(b, dev.BusName)
+	data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
+	req.AddData(data)
+
+	b = make([]byte, len(dev.DeviceName))
+	copy(b, dev.DeviceName)
+	data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
+	req.AddData(data)
+
+	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
+	if err != nil {
+		return
+	}
+	dev.parseEswitchAttrs(msgs)
+}
+
+// DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
+// otherwise returns an error code.
+func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
+	f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
+	if err != nil {
+		return nil, err
+	}
+	msg := &nl.Genlmsg{
+		Command: nl.DEVLINK_CMD_GET,
+		Version: nl.GENL_DEVLINK_VERSION,
+	}
+	req := h.newNetlinkRequest(int(f.ID),
+		unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
+	req.AddData(msg)
+	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
+	if err != nil {
+		return nil, err
+	}
+	devices, err := parseDevLinkDeviceList(msgs)
+	if err != nil {
+		return nil, err
+	}
+	for _, d := range devices {
+		h.getEswitchAttrs(f, d)
+	}
+	return devices, nil
+}
+
+// DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
+// otherwise returns an error code.
+func DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
+	return pkgHandle.DevLinkGetDeviceList()
+}
+
+func parseDevlinkDevice(msgs [][]byte) (*DevlinkDevice, error) {
+	m := msgs[0]
+	attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
+	if err != nil {
+		return nil, err
+	}
+	dev := &DevlinkDevice{}
+	if err = dev.parseAttributes(attrs); err != nil {
+		return nil, err
+	}
+	return dev, nil
+}
+
+func (h *Handle) createCmdReq(cmd uint8, bus string, device string) (*GenlFamily, *nl.NetlinkRequest, error) {
+	f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	msg := &nl.Genlmsg{
+		Command: cmd,
+		Version: nl.GENL_DEVLINK_VERSION,
+	}
+	req := h.newNetlinkRequest(int(f.ID),
+		unix.NLM_F_REQUEST|unix.NLM_F_ACK)
+	req.AddData(msg)
+
+	b := make([]byte, len(bus)+1)
+	copy(b, bus)
+	data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
+	req.AddData(data)
+
+	b = make([]byte, len(device)+1)
+	copy(b, device)
+	data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
+	req.AddData(data)
+
+	return f, req, nil
+}
+
+// DevlinkGetDeviceByName provides a pointer to devlink device and nil error,
+// otherwise returns an error code.
+func (h *Handle) DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) {
+	f, req, err := h.createCmdReq(nl.DEVLINK_CMD_GET, Bus, Device)
+	if err != nil {
+		return nil, err
+	}
+
+	respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
+	if err != nil {
+		return nil, err
+	}
+	dev, err := parseDevlinkDevice(respmsg)
+	if err == nil {
+		h.getEswitchAttrs(f, dev)
+	}
+	return dev, err
+}
+
+// DevlinkGetDeviceByName provides a pointer to devlink device and nil error,
+// otherwise returns an error code.
+func DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) {
+	return pkgHandle.DevLinkGetDeviceByName(Bus, Device)
+}
+
+// DevLinkSetEswitchMode sets eswitch mode if able to set successfully or
+// returns an error code.
+// Equivalent to: `devlink dev eswitch set $dev mode switchdev`
+// Equivalent to: `devlink dev eswitch set $dev mode legacy`
+func (h *Handle) DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
+	mode, err := eswitchStringToMode(NewMode)
+	if err != nil {
+		return err
+	}
+
+	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_ESWITCH_SET, Dev.BusName, Dev.DeviceName)
+	if err != nil {
+		return err
+	}
+
+	req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_ESWITCH_MODE, nl.Uint16Attr(mode)))
+
+	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
+	return err
+}
+
+// DevLinkSetEswitchMode sets eswitch mode if able to set successfully or
+// returns an error code.
+// Equivalent to: `devlink dev eswitch set $dev mode switchdev`
+// Equivalent to: `devlink dev eswitch set $dev mode legacy`
+func DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
+	return pkgHandle.DevLinkSetEswitchMode(Dev, NewMode)
+}

+ 73 - 37
vendor/github.com/vishvananda/netlink/filter.go

@@ -2,6 +2,7 @@ package netlink
 
 import (
 	"fmt"
+	"net"
 )
 
 type Filter interface {
@@ -135,6 +136,27 @@ func (action *BpfAction) Attrs() *ActionAttrs {
 	return &action.ActionAttrs
 }
 
+type ConnmarkAction struct {
+	ActionAttrs
+	Zone uint16
+}
+
+func (action *ConnmarkAction) Type() string {
+	return "connmark"
+}
+
+func (action *ConnmarkAction) Attrs() *ActionAttrs {
+	return &action.ActionAttrs
+}
+
+func NewConnmarkAction() *ConnmarkAction {
+	return &ConnmarkAction{
+		ActionAttrs: ActionAttrs{
+			Action: TC_ACT_PIPE,
+		},
+	}
+}
+
 type MirredAct uint8
 
 func (a MirredAct) String() string {
@@ -182,47 +204,59 @@ func NewMirredAction(redirIndex int) *MirredAction {
 	}
 }
 
-// Sel of the U32 filters that contains multiple TcU32Key. This is the copy
-// and the frontend representation of nl.TcU32Sel. It is serialized into canonical
-// nl.TcU32Sel with the appropriate endianness.
-type TcU32Sel struct {
-	Flags    uint8
-	Offshift uint8
-	Nkeys    uint8
-	Pad      uint8
-	Offmask  uint16
-	Off      uint16
-	Offoff   int16
-	Hoff     int16
-	Hmask    uint32
-	Keys     []TcU32Key
-}
-
-// TcU32Key contained of Sel in the U32 filters. This is the copy and the frontend
-// representation of nl.TcU32Key. It is serialized into chanonical nl.TcU32Sel
-// with the appropriate endianness.
-type TcU32Key struct {
-	Mask    uint32
-	Val     uint32
-	Off     int32
-	OffMask int32
-}
-
-// U32 filters on many packet related properties
-type U32 struct {
-	FilterAttrs
-	ClassId    uint32
-	RedirIndex int
-	Sel        *TcU32Sel
-	Actions    []Action
+type TunnelKeyAct int8
+
+const (
+	TCA_TUNNEL_KEY_SET   TunnelKeyAct = 1 // set tunnel key
+	TCA_TUNNEL_KEY_UNSET TunnelKeyAct = 2 // unset tunnel key
+)
+
+type TunnelKeyAction struct {
+	ActionAttrs
+	Action  TunnelKeyAct
+	SrcAddr net.IP
+	DstAddr net.IP
+	KeyID   uint32
 }
 
-func (filter *U32) Attrs() *FilterAttrs {
-	return &filter.FilterAttrs
+func (action *TunnelKeyAction) Type() string {
+	return "tunnel_key"
 }
 
-func (filter *U32) Type() string {
-	return "u32"
+func (action *TunnelKeyAction) Attrs() *ActionAttrs {
+	return &action.ActionAttrs
+}
+
+func NewTunnelKeyAction() *TunnelKeyAction {
+	return &TunnelKeyAction{
+		ActionAttrs: ActionAttrs{
+			Action: TC_ACT_PIPE,
+		},
+	}
+}
+
+type SkbEditAction struct {
+	ActionAttrs
+	QueueMapping *uint16
+	PType        *uint16
+	Priority     *uint32
+	Mark         *uint32
+}
+
+func (action *SkbEditAction) Type() string {
+	return "skbedit"
+}
+
+func (action *SkbEditAction) Attrs() *ActionAttrs {
+	return &action.ActionAttrs
+}
+
+func NewSkbEditAction() *SkbEditAction {
+	return &SkbEditAction{
+		ActionAttrs: ActionAttrs{
+			Action: TC_ACT_PIPE,
+		},
+	}
 }
 
 // MatchAll filters match all packets
@@ -262,6 +296,8 @@ type BpfFilter struct {
 	Fd           int
 	Name         string
 	DirectAction bool
+	Id           int
+	Tag          string
 }
 
 func (filter *BpfFilter) Type() string {

+ 204 - 36
vendor/github.com/vishvananda/netlink/filter_linux.go

@@ -3,10 +3,11 @@ package netlink
 import (
 	"bytes"
 	"encoding/binary"
+	"encoding/hex"
 	"errors"
 	"fmt"
+	"net"
 	"syscall"
-	"unsafe"
 
 	"github.com/vishvananda/netlink/nl"
 	"golang.org/x/sys/unix"
@@ -20,6 +21,35 @@ const (
 	TC_U32_EAT       = nl.TC_U32_EAT
 )
 
+// Sel of the U32 filters that contains multiple TcU32Key. This is the type
+// alias and the frontend representation of nl.TcU32Sel. It is serialized into
+// canonical nl.TcU32Sel with the appropriate endianness.
+type TcU32Sel = nl.TcU32Sel
+
+// TcU32Key contained of Sel in the U32 filters. This is the type alias and the
+// frontend representation of nl.TcU32Key. It is serialized into chanonical
+// nl.TcU32Sel with the appropriate endianness.
+type TcU32Key = nl.TcU32Key
+
+// U32 filters on many packet related properties
+type U32 struct {
+	FilterAttrs
+	ClassId    uint32
+	Divisor    uint32 // Divisor MUST be power of 2.
+	Hash       uint32
+	RedirIndex int
+	Sel        *TcU32Sel
+	Actions    []Action
+}
+
+func (filter *U32) Attrs() *FilterAttrs {
+	return &filter.FilterAttrs
+}
+
+func (filter *U32) Type() string {
+	return "u32"
+}
+
 // Fw filter filters on firewall marks
 // NOTE: this is in filter_linux because it refers to nl.TcPolice which
 //       is defined in nl/tc_linux.go
@@ -123,8 +153,24 @@ func FilterAdd(filter Filter) error {
 // FilterAdd will add a filter to the system.
 // Equivalent to: `tc filter add $filter`
 func (h *Handle) FilterAdd(filter Filter) error {
+	return h.filterModify(filter, unix.NLM_F_CREATE|unix.NLM_F_EXCL)
+}
+
+// FilterReplace will replace a filter.
+// Equivalent to: `tc filter replace $filter`
+func FilterReplace(filter Filter) error {
+	return pkgHandle.FilterReplace(filter)
+}
+
+// FilterReplace will replace a filter.
+// Equivalent to: `tc filter replace $filter`
+func (h *Handle) FilterReplace(filter Filter) error {
+	return h.filterModify(filter, unix.NLM_F_CREATE)
+}
+
+func (h *Handle) filterModify(filter Filter, flags int) error {
 	native = nl.NativeEndian()
-	req := h.newNetlinkRequest(unix.RTM_NEWTFILTER, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
+	req := h.newNetlinkRequest(unix.RTM_NEWTFILTER, flags|unix.NLM_F_ACK)
 	base := filter.Attrs()
 	msg := &nl.TcMsg{
 		Family:  nl.FAMILY_ALL,
@@ -140,8 +186,7 @@ func (h *Handle) FilterAdd(filter Filter) error {
 
 	switch filter := filter.(type) {
 	case *U32:
-		// Convert TcU32Sel into nl.TcU32Sel as it is without copy.
-		sel := (*nl.TcU32Sel)(unsafe.Pointer(filter.Sel))
+		sel := filter.Sel
 		if sel == nil {
 			// match all
 			sel = &nl.TcU32Sel{
@@ -168,11 +213,20 @@ func (h *Handle) FilterAdd(filter Filter) error {
 			}
 		}
 		sel.Nkeys = uint8(len(sel.Keys))
-		nl.NewRtAttrChild(options, nl.TCA_U32_SEL, sel.Serialize())
+		options.AddRtAttr(nl.TCA_U32_SEL, sel.Serialize())
 		if filter.ClassId != 0 {
-			nl.NewRtAttrChild(options, nl.TCA_U32_CLASSID, nl.Uint32Attr(filter.ClassId))
+			options.AddRtAttr(nl.TCA_U32_CLASSID, nl.Uint32Attr(filter.ClassId))
+		}
+		if filter.Divisor != 0 {
+			if (filter.Divisor-1)&filter.Divisor != 0 {
+				return fmt.Errorf("illegal divisor %d. Must be a power of 2", filter.Divisor)
+			}
+			options.AddRtAttr(nl.TCA_U32_DIVISOR, nl.Uint32Attr(filter.Divisor))
 		}
-		actionsAttr := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil)
+		if filter.Hash != 0 {
+			options.AddRtAttr(nl.TCA_U32_HASH, nl.Uint32Attr(filter.Hash))
+		}
+		actionsAttr := options.AddRtAttr(nl.TCA_U32_ACT, nil)
 		// backwards compatibility
 		if filter.RedirIndex != 0 {
 			filter.Actions = append([]Action{NewMirredAction(filter.RedirIndex)}, filter.Actions...)
@@ -184,51 +238,51 @@ func (h *Handle) FilterAdd(filter Filter) error {
 		if filter.Mask != 0 {
 			b := make([]byte, 4)
 			native.PutUint32(b, filter.Mask)
-			nl.NewRtAttrChild(options, nl.TCA_FW_MASK, b)
+			options.AddRtAttr(nl.TCA_FW_MASK, b)
 		}
 		if filter.InDev != "" {
-			nl.NewRtAttrChild(options, nl.TCA_FW_INDEV, nl.ZeroTerminated(filter.InDev))
+			options.AddRtAttr(nl.TCA_FW_INDEV, nl.ZeroTerminated(filter.InDev))
 		}
 		if (filter.Police != nl.TcPolice{}) {
 
-			police := nl.NewRtAttrChild(options, nl.TCA_FW_POLICE, nil)
-			nl.NewRtAttrChild(police, nl.TCA_POLICE_TBF, filter.Police.Serialize())
+			police := options.AddRtAttr(nl.TCA_FW_POLICE, nil)
+			police.AddRtAttr(nl.TCA_POLICE_TBF, filter.Police.Serialize())
 			if (filter.Police.Rate != nl.TcRateSpec{}) {
 				payload := SerializeRtab(filter.Rtab)
-				nl.NewRtAttrChild(police, nl.TCA_POLICE_RATE, payload)
+				police.AddRtAttr(nl.TCA_POLICE_RATE, payload)
 			}
 			if (filter.Police.PeakRate != nl.TcRateSpec{}) {
 				payload := SerializeRtab(filter.Ptab)
-				nl.NewRtAttrChild(police, nl.TCA_POLICE_PEAKRATE, payload)
+				police.AddRtAttr(nl.TCA_POLICE_PEAKRATE, payload)
 			}
 		}
 		if filter.ClassId != 0 {
 			b := make([]byte, 4)
 			native.PutUint32(b, filter.ClassId)
-			nl.NewRtAttrChild(options, nl.TCA_FW_CLASSID, b)
+			options.AddRtAttr(nl.TCA_FW_CLASSID, b)
 		}
 	case *BpfFilter:
 		var bpfFlags uint32
 		if filter.ClassId != 0 {
-			nl.NewRtAttrChild(options, nl.TCA_BPF_CLASSID, nl.Uint32Attr(filter.ClassId))
+			options.AddRtAttr(nl.TCA_BPF_CLASSID, nl.Uint32Attr(filter.ClassId))
 		}
 		if filter.Fd >= 0 {
-			nl.NewRtAttrChild(options, nl.TCA_BPF_FD, nl.Uint32Attr((uint32(filter.Fd))))
+			options.AddRtAttr(nl.TCA_BPF_FD, nl.Uint32Attr((uint32(filter.Fd))))
 		}
 		if filter.Name != "" {
-			nl.NewRtAttrChild(options, nl.TCA_BPF_NAME, nl.ZeroTerminated(filter.Name))
+			options.AddRtAttr(nl.TCA_BPF_NAME, nl.ZeroTerminated(filter.Name))
 		}
 		if filter.DirectAction {
 			bpfFlags |= nl.TCA_BPF_FLAG_ACT_DIRECT
 		}
-		nl.NewRtAttrChild(options, nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags))
+		options.AddRtAttr(nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags))
 	case *MatchAll:
-		actionsAttr := nl.NewRtAttrChild(options, nl.TCA_MATCHALL_ACT, nil)
+		actionsAttr := options.AddRtAttr(nl.TCA_MATCHALL_ACT, nil)
 		if err := EncodeActions(actionsAttr, filter.Actions); err != nil {
 			return err
 		}
 		if filter.ClassId != 0 {
-			nl.NewRtAttrChild(options, nl.TCA_MATCHALL_CLASSID, nl.Uint32Attr(filter.ClassId))
+			options.AddRtAttr(nl.TCA_MATCHALL_CLASSID, nl.Uint32Attr(filter.ClassId))
 		}
 	}
 
@@ -366,34 +420,91 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error {
 		default:
 			return fmt.Errorf("unknown action type %s", action.Type())
 		case *MirredAction:
-			table := nl.NewRtAttrChild(attr, tabIndex, nil)
+			table := attr.AddRtAttr(tabIndex, nil)
 			tabIndex++
-			nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("mirred"))
-			aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil)
+			table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("mirred"))
+			aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
 			mirred := nl.TcMirred{
 				Eaction: int32(action.MirredAction),
 				Ifindex: uint32(action.Ifindex),
 			}
 			toTcGen(action.Attrs(), &mirred.TcGen)
-			nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, mirred.Serialize())
+			aopts.AddRtAttr(nl.TCA_MIRRED_PARMS, mirred.Serialize())
+		case *TunnelKeyAction:
+			table := attr.AddRtAttr(tabIndex, nil)
+			tabIndex++
+			table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("tunnel_key"))
+			aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
+			tun := nl.TcTunnelKey{
+				Action: int32(action.Action),
+			}
+			toTcGen(action.Attrs(), &tun.TcGen)
+			aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_PARMS, tun.Serialize())
+			if action.Action == TCA_TUNNEL_KEY_SET {
+				aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_KEY_ID, htonl(action.KeyID))
+				if v4 := action.SrcAddr.To4(); v4 != nil {
+					aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV4_SRC, v4[:])
+				} else if v6 := action.SrcAddr.To16(); v6 != nil {
+					aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV6_SRC, v6[:])
+				} else {
+					return fmt.Errorf("invalid src addr %s for tunnel_key action", action.SrcAddr)
+				}
+				if v4 := action.DstAddr.To4(); v4 != nil {
+					aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV4_DST, v4[:])
+				} else if v6 := action.DstAddr.To16(); v6 != nil {
+					aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV6_DST, v6[:])
+				} else {
+					return fmt.Errorf("invalid dst addr %s for tunnel_key action", action.DstAddr)
+				}
+			}
+		case *SkbEditAction:
+			table := attr.AddRtAttr(tabIndex, nil)
+			tabIndex++
+			table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("skbedit"))
+			aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
+			skbedit := nl.TcSkbEdit{}
+			toTcGen(action.Attrs(), &skbedit.TcGen)
+			aopts.AddRtAttr(nl.TCA_SKBEDIT_PARMS, skbedit.Serialize())
+			if action.QueueMapping != nil {
+				aopts.AddRtAttr(nl.TCA_SKBEDIT_QUEUE_MAPPING, nl.Uint16Attr(*action.QueueMapping))
+			}
+			if action.Priority != nil {
+				aopts.AddRtAttr(nl.TCA_SKBEDIT_PRIORITY, nl.Uint32Attr(*action.Priority))
+			}
+			if action.PType != nil {
+				aopts.AddRtAttr(nl.TCA_SKBEDIT_PTYPE, nl.Uint16Attr(*action.PType))
+			}
+			if action.Mark != nil {
+				aopts.AddRtAttr(nl.TCA_SKBEDIT_MARK, nl.Uint32Attr(*action.Mark))
+			}
+		case *ConnmarkAction:
+			table := attr.AddRtAttr(tabIndex, nil)
+			tabIndex++
+			table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("connmark"))
+			aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
+			connmark := nl.TcConnmark{
+				Zone: action.Zone,
+			}
+			toTcGen(action.Attrs(), &connmark.TcGen)
+			aopts.AddRtAttr(nl.TCA_CONNMARK_PARMS, connmark.Serialize())
 		case *BpfAction:
-			table := nl.NewRtAttrChild(attr, tabIndex, nil)
+			table := attr.AddRtAttr(tabIndex, nil)
 			tabIndex++
-			nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("bpf"))
-			aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil)
+			table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("bpf"))
+			aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
 			gen := nl.TcGen{}
 			toTcGen(action.Attrs(), &gen)
-			nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_PARMS, gen.Serialize())
-			nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd)))
-			nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name))
+			aopts.AddRtAttr(nl.TCA_ACT_BPF_PARMS, gen.Serialize())
+			aopts.AddRtAttr(nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd)))
+			aopts.AddRtAttr(nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name))
 		case *GenericAction:
-			table := nl.NewRtAttrChild(attr, tabIndex, nil)
+			table := attr.AddRtAttr(tabIndex, nil)
 			tabIndex++
-			nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("gact"))
-			aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil)
+			table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("gact"))
+			aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
 			gen := nl.TcGen{}
 			toTcGen(action.Attrs(), &gen)
-			nl.NewRtAttrChild(aopts, nl.TCA_GACT_PARMS, gen.Serialize())
+			aopts.AddRtAttr(nl.TCA_GACT_PARMS, gen.Serialize())
 		}
 	}
 	return nil
@@ -419,8 +530,14 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
 					action = &MirredAction{}
 				case "bpf":
 					action = &BpfAction{}
+				case "connmark":
+					action = &ConnmarkAction{}
 				case "gact":
 					action = &GenericAction{}
+				case "tunnel_key":
+					action = &TunnelKeyAction{}
+				case "skbedit":
+					action = &SkbEditAction{}
 				default:
 					break nextattr
 				}
@@ -435,11 +552,46 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
 						switch adatum.Attr.Type {
 						case nl.TCA_MIRRED_PARMS:
 							mirred := *nl.DeserializeTcMirred(adatum.Value)
-							toAttrs(&mirred.TcGen, action.Attrs())
 							action.(*MirredAction).ActionAttrs = ActionAttrs{}
+							toAttrs(&mirred.TcGen, action.Attrs())
 							action.(*MirredAction).Ifindex = int(mirred.Ifindex)
 							action.(*MirredAction).MirredAction = MirredAct(mirred.Eaction)
 						}
+					case "tunnel_key":
+						switch adatum.Attr.Type {
+						case nl.TCA_TUNNEL_KEY_PARMS:
+							tun := *nl.DeserializeTunnelKey(adatum.Value)
+							action.(*TunnelKeyAction).ActionAttrs = ActionAttrs{}
+							toAttrs(&tun.TcGen, action.Attrs())
+							action.(*TunnelKeyAction).Action = TunnelKeyAct(tun.Action)
+						case nl.TCA_TUNNEL_KEY_ENC_KEY_ID:
+							action.(*TunnelKeyAction).KeyID = networkOrder.Uint32(adatum.Value[0:4])
+						case nl.TCA_TUNNEL_KEY_ENC_IPV6_SRC:
+						case nl.TCA_TUNNEL_KEY_ENC_IPV4_SRC:
+							action.(*TunnelKeyAction).SrcAddr = net.IP(adatum.Value[:])
+						case nl.TCA_TUNNEL_KEY_ENC_IPV6_DST:
+						case nl.TCA_TUNNEL_KEY_ENC_IPV4_DST:
+							action.(*TunnelKeyAction).DstAddr = net.IP(adatum.Value[:])
+						}
+					case "skbedit":
+						switch adatum.Attr.Type {
+						case nl.TCA_SKBEDIT_PARMS:
+							skbedit := *nl.DeserializeSkbEdit(adatum.Value)
+							action.(*SkbEditAction).ActionAttrs = ActionAttrs{}
+							toAttrs(&skbedit.TcGen, action.Attrs())
+						case nl.TCA_SKBEDIT_MARK:
+							mark := native.Uint32(adatum.Value[0:4])
+							action.(*SkbEditAction).Mark = &mark
+						case nl.TCA_SKBEDIT_PRIORITY:
+							priority := native.Uint32(adatum.Value[0:4])
+							action.(*SkbEditAction).Priority = &priority
+						case nl.TCA_SKBEDIT_PTYPE:
+							ptype := native.Uint16(adatum.Value[0:2])
+							action.(*SkbEditAction).PType = &ptype
+						case nl.TCA_SKBEDIT_QUEUE_MAPPING:
+							mapping := native.Uint16(adatum.Value[0:2])
+							action.(*SkbEditAction).QueueMapping = &mapping
+						}
 					case "bpf":
 						switch adatum.Attr.Type {
 						case nl.TCA_ACT_BPF_PARMS:
@@ -450,6 +602,14 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
 						case nl.TCA_ACT_BPF_NAME:
 							action.(*BpfAction).Name = string(adatum.Value[:len(adatum.Value)-1])
 						}
+					case "connmark":
+						switch adatum.Attr.Type {
+						case nl.TCA_CONNMARK_PARMS:
+							connmark := *nl.DeserializeTcConnmark(adatum.Value)
+							action.(*ConnmarkAction).ActionAttrs = ActionAttrs{}
+							toAttrs(&connmark.TcGen, action.Attrs())
+							action.(*ConnmarkAction).Zone = connmark.Zone
+						}
 					case "gact":
 						switch adatum.Attr.Type {
 						case nl.TCA_GACT_PARMS:
@@ -474,7 +634,7 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
 		case nl.TCA_U32_SEL:
 			detailed = true
 			sel := nl.DeserializeTcU32Sel(datum.Value)
-			u32.Sel = (*TcU32Sel)(unsafe.Pointer(sel))
+			u32.Sel = sel
 			if native != networkOrder {
 				// Handle the endianness of attributes
 				u32.Sel.Offmask = native.Uint16(htons(sel.Offmask))
@@ -500,6 +660,10 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
 			}
 		case nl.TCA_U32_CLASSID:
 			u32.ClassId = native.Uint32(datum.Value)
+		case nl.TCA_U32_DIVISOR:
+			u32.Divisor = native.Uint32(datum.Value)
+		case nl.TCA_U32_HASH:
+			u32.Hash = native.Uint32(datum.Value)
 		}
 	}
 	return detailed, nil
@@ -551,6 +715,10 @@ func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
 			if (flags & nl.TCA_BPF_FLAG_ACT_DIRECT) != 0 {
 				bpf.DirectAction = true
 			}
+		case nl.TCA_BPF_ID:
+			bpf.Id = int(native.Uint32(datum.Value[0:4]))
+		case nl.TCA_BPF_TAG:
+			bpf.Tag = hex.EncodeToString(datum.Value[:len(datum.Value)-1])
 		}
 	}
 	return detailed, nil

+ 1 - 5
vendor/github.com/vishvananda/netlink/fou_linux.go

@@ -90,11 +90,7 @@ func (h *Handle) FouAdd(f Fou) error {
 	req.AddRawData(raw)
 
 	_, err = req.Execute(unix.NETLINK_GENERIC, 0)
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return err
 }
 
 func FouDel(f Fou) error {

+ 3 - 0
vendor/github.com/vishvananda/netlink/genetlink_linux.go

@@ -157,6 +157,9 @@ func (h *Handle) GenlFamilyGet(name string) (*GenlFamily, error) {
 		return nil, err
 	}
 	families, err := parseFamilies(msgs)
+	if err != nil {
+		return nil, err
+	}
 	if len(families) != 1 {
 		return nil, fmt.Errorf("invalid response for GENL_CTRL_CMD_GETFAMILY")
 	}

+ 8 - 0
vendor/github.com/vishvananda/netlink/go.mod

@@ -0,0 +1,8 @@
+module github.com/vishvananda/netlink
+
+go 1.12
+
+require (
+	github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df
+	golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444
+)

+ 1 - 1
vendor/github.com/vishvananda/netlink/handle_linux.go

@@ -91,7 +91,7 @@ func (h *Handle) GetSocketReceiveBufferSize() ([]int, error) {
 	return results, nil
 }
 
-// NewHandle returns a netlink handle on the network namespace
+// NewHandleAt returns a netlink handle on the network namespace
 // specified by ns. If ns=netns.None(), current network namespace
 // will be assumed
 func NewHandleAt(ns netns.NsHandle, nlFamilies ...int) (*Handle, error) {

+ 12 - 0
vendor/github.com/vishvananda/netlink/handle_unspecified.go

@@ -73,10 +73,18 @@ func (h *Handle) LinkSetVfVlan(link Link, vf, vlan int) error {
 	return ErrNotImplemented
 }
 
+func (h *Handle) LinkSetVfVlanQos(link Link, vf, vlan, qos int) error {
+	return ErrNotImplemented
+}
+
 func (h *Handle) LinkSetVfTxRate(link Link, vf, rate int) error {
 	return ErrNotImplemented
 }
 
+func (h *Handle) LinkSetVfRate(link Link, vf, minRate, maxRate int) error {
+	return ErrNotImplemented
+}
+
 func (h *Handle) LinkSetMaster(link Link, master *Bridge) error {
 	return ErrNotImplemented
 }
@@ -149,6 +157,10 @@ func (h *Handle) LinkSetTxQLen(link Link, qlen int) error {
 	return ErrNotImplemented
 }
 
+func (h *Handle) LinkSetGroup(link Link, group int) error {
+	return ErrNotImplemented
+}
+
 func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
 	return ErrNotImplemented
 }

+ 1 - 9
vendor/github.com/vishvananda/netlink/ioctl_linux.go

@@ -56,18 +56,10 @@ type ethtoolSset struct {
 	data     [1]uint32
 }
 
-// ethtoolGstrings is string set for data tagging
-type ethtoolGstrings struct {
-	cmd       uint32
-	stringSet uint32
-	length    uint32
-	data      [32]byte
-}
-
 type ethtoolStats struct {
 	cmd    uint32
 	nStats uint32
-	data   [1]uint64
+	// Followed by nStats * []uint64.
 }
 
 // newIocltSlaveReq returns filled IfreqSlave with proper interface names

+ 230 - 12
vendor/github.com/vishvananda/netlink/link.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"net"
 	"os"
+	"strconv"
 )
 
 // Link represents a link device from netlink. Shared link attributes
@@ -41,6 +42,29 @@ type LinkAttrs struct {
 	NetNsID      int
 	NumTxQueues  int
 	NumRxQueues  int
+	GSOMaxSize   uint32
+	GSOMaxSegs   uint32
+	Vfs          []VfInfo // virtual functions available on link
+	Group        uint32
+	Slave        LinkSlave
+}
+
+// LinkSlave represents a slave device.
+type LinkSlave interface {
+	SlaveType() string
+}
+
+// VfInfo represents configuration of virtual function
+type VfInfo struct {
+	ID        int
+	Mac       net.HardwareAddr
+	Vlan      int
+	Qos       int
+	TxRate    int // IFLA_VF_TX_RATE  Max TxRate
+	Spoofchk  bool
+	LinkState uint32
+	MaxTxRate uint32 // IFLA_VF_RATE Max TxRate
+	MinTxRate uint32 // IFLA_VF_RATE Min TxRate
 }
 
 // LinkOperState represents the values of the IFLA_OPERSTATE link
@@ -223,6 +247,7 @@ type Bridge struct {
 	LinkAttrs
 	MulticastSnooping *bool
 	HelloTime         *uint32
+	VlanFiltering     *bool
 }
 
 func (bridge *Bridge) Attrs() *LinkAttrs {
@@ -236,7 +261,8 @@ func (bridge *Bridge) Type() string {
 // Vlan links have ParentIndex set in their Attrs()
 type Vlan struct {
 	LinkAttrs
-	VlanId int
+	VlanId       int
+	VlanProtocol VlanProtocol
 }
 
 func (vlan *Vlan) Attrs() *LinkAttrs {
@@ -290,10 +316,13 @@ type TuntapFlag uint16
 // Tuntap links created via /dev/tun/tap, but can be destroyed via netlink
 type Tuntap struct {
 	LinkAttrs
-	Mode   TuntapMode
-	Flags  TuntapFlag
-	Queues int
-	Fds    []*os.File
+	Mode       TuntapMode
+	Flags      TuntapFlag
+	NonPersist bool
+	Queues     int
+	Fds        []*os.File
+	Owner      uint32
+	Group      uint32
 }
 
 func (tuntap *Tuntap) Attrs() *LinkAttrs {
@@ -307,7 +336,8 @@ func (tuntap *Tuntap) Type() string {
 // Veth devices must specify PeerName on create
 type Veth struct {
 	LinkAttrs
-	PeerName string // veth on create only
+	PeerName         string // veth on create only
+	PeerHardwareAddr net.HardwareAddr
 }
 
 func (veth *Veth) Attrs() *LinkAttrs {
@@ -376,9 +406,18 @@ const (
 	IPVLAN_MODE_MAX
 )
 
+type IPVlanFlag uint16
+
+const (
+	IPVLAN_FLAG_BRIDGE IPVlanFlag = iota
+	IPVLAN_FLAG_PRIVATE
+	IPVLAN_FLAG_VEPA
+)
+
 type IPVlan struct {
 	LinkAttrs
 	Mode IPVlanMode
+	Flag IPVlanFlag
 }
 
 func (ipvlan *IPVlan) Attrs() *LinkAttrs {
@@ -389,6 +428,43 @@ func (ipvlan *IPVlan) Type() string {
 	return "ipvlan"
 }
 
+// VlanProtocol type
+type VlanProtocol int
+
+func (p VlanProtocol) String() string {
+	s, ok := VlanProtocolToString[p]
+	if !ok {
+		return fmt.Sprintf("VlanProtocol(%d)", p)
+	}
+	return s
+}
+
+// StringToVlanProtocol returns vlan protocol, or unknown is the s is invalid.
+func StringToVlanProtocol(s string) VlanProtocol {
+	mode, ok := StringToVlanProtocolMap[s]
+	if !ok {
+		return VLAN_PROTOCOL_UNKNOWN
+	}
+	return mode
+}
+
+// VlanProtocol possible values
+const (
+	VLAN_PROTOCOL_UNKNOWN VlanProtocol = 0
+	VLAN_PROTOCOL_8021Q   VlanProtocol = 0x8100
+	VLAN_PROTOCOL_8021AD  VlanProtocol = 0x88A8
+)
+
+var VlanProtocolToString = map[VlanProtocol]string{
+	VLAN_PROTOCOL_8021Q:  "802.1q",
+	VLAN_PROTOCOL_8021AD: "802.1ad",
+}
+
+var StringToVlanProtocolMap = map[string]VlanProtocol{
+	"802.1q":  VLAN_PROTOCOL_8021Q,
+	"802.1ad": VLAN_PROTOCOL_8021AD,
+}
+
 // BondMode type
 type BondMode int
 
@@ -400,7 +476,7 @@ func (b BondMode) String() string {
 	return s
 }
 
-// StringToBondMode returns bond mode, or uknonw is the s is invalid.
+// StringToBondMode returns bond mode, or unknown is the s is invalid.
 func StringToBondMode(s string) BondMode {
 	mode, ok := StringToBondModeMap[s]
 	if !ok {
@@ -491,7 +567,7 @@ func (b BondXmitHashPolicy) String() string {
 	return s
 }
 
-// StringToBondXmitHashPolicy returns bond lacp arte, or uknonw is the s is invalid.
+// StringToBondXmitHashPolicy returns bond lacp arte, or unknown is the s is invalid.
 func StringToBondXmitHashPolicy(s string) BondXmitHashPolicy {
 	lacp, ok := StringToBondXmitHashPolicyMap[s]
 	if !ok {
@@ -536,7 +612,7 @@ func (b BondLacpRate) String() string {
 	return s
 }
 
-// StringToBondLacpRate returns bond lacp arte, or uknonw is the s is invalid.
+// StringToBondLacpRate returns bond lacp arte, or unknown is the s is invalid.
 func StringToBondLacpRate(s string) BondLacpRate {
 	lacp, ok := StringToBondLacpRateMap[s]
 	if !ok {
@@ -680,6 +756,67 @@ func (bond *Bond) Type() string {
 	return "bond"
 }
 
+// BondSlaveState represents the values of the IFLA_BOND_SLAVE_STATE bond slave
+// attribute, which contains the state of the bond slave.
+type BondSlaveState uint8
+
+const (
+	BondStateActive = iota // Link is active.
+	BondStateBackup        // Link is backup.
+)
+
+func (s BondSlaveState) String() string {
+	switch s {
+	case BondStateActive:
+		return "ACTIVE"
+	case BondStateBackup:
+		return "BACKUP"
+	default:
+		return strconv.Itoa(int(s))
+	}
+}
+
+// BondSlaveState represents the values of the IFLA_BOND_SLAVE_MII_STATUS bond slave
+// attribute, which contains the status of MII link monitoring
+type BondSlaveMiiStatus uint8
+
+const (
+	BondLinkUp   = iota // link is up and running.
+	BondLinkFail        // link has just gone down.
+	BondLinkDown        // link has been down for too long time.
+	BondLinkBack        // link is going back.
+)
+
+func (s BondSlaveMiiStatus) String() string {
+	switch s {
+	case BondLinkUp:
+		return "UP"
+	case BondLinkFail:
+		return "GOING_DOWN"
+	case BondLinkDown:
+		return "DOWN"
+	case BondLinkBack:
+		return "GOING_BACK"
+	default:
+		return strconv.Itoa(int(s))
+	}
+}
+
+type BondSlave struct {
+	State                  BondSlaveState
+	MiiStatus              BondSlaveMiiStatus
+	LinkFailureCount       uint32
+	PermHardwareAddr       net.HardwareAddr
+	QueueId                uint16
+	AggregatorId           uint16
+	AdActorOperPortState   uint8
+	AdPartnerOperPortState uint16
+}
+
+func (b *BondSlave) SlaveType() string {
+	return "bond"
+}
+
 // Gretap devices must specify LocalIP and RemoteIP on create
 type Gretap struct {
 	LinkAttrs
@@ -734,6 +871,27 @@ func (iptun *Iptun) Type() string {
 	return "ipip"
 }
 
+type Ip6tnl struct {
+	LinkAttrs
+	Link       uint32
+	Local      net.IP
+	Remote     net.IP
+	Ttl        uint8
+	Tos        uint8
+	EncapLimit uint8
+	Flags      uint32
+	Proto      uint8
+	FlowInfo   uint32
+}
+
+func (ip6tnl *Ip6tnl) Attrs() *LinkAttrs {
+	return &ip6tnl.LinkAttrs
+}
+
+func (ip6tnl *Ip6tnl) Type() string {
+	return "ip6tnl"
+}
+
 type Sittun struct {
 	LinkAttrs
 	Link       uint32
@@ -769,7 +927,10 @@ func (vti *Vti) Attrs() *LinkAttrs {
 	return &vti.LinkAttrs
 }
 
-func (iptun *Vti) Type() string {
+func (vti *Vti) Type() string {
+	if vti.Local.To4() == nil {
+		return "vti6"
+	}
 	return "vti"
 }
 
@@ -831,11 +992,68 @@ func (gtp *GTP) Type() string {
 	return "gtp"
 }
 
+// Virtual XFRM Interfaces
+//	Named "xfrmi" to prevent confusion with XFRM objects
+type Xfrmi struct {
+	LinkAttrs
+	Ifid uint32
+}
+
+func (xfrm *Xfrmi) Attrs() *LinkAttrs {
+	return &xfrm.LinkAttrs
+}
+
+func (xfrm *Xfrmi) Type() string {
+	return "xfrm"
+}
+
+// IPoIB interface
+
+type IPoIBMode uint16
+
+func (m *IPoIBMode) String() string {
+	str, ok := iPoIBModeToString[*m]
+	if !ok {
+		return fmt.Sprintf("mode(%d)", *m)
+	}
+	return str
+}
+
+const (
+	IPOIB_MODE_DATAGRAM = iota
+	IPOIB_MODE_CONNECTED
+)
+
+var iPoIBModeToString = map[IPoIBMode]string{
+	IPOIB_MODE_DATAGRAM:  "datagram",
+	IPOIB_MODE_CONNECTED: "connected",
+}
+
+var StringToIPoIBMode = map[string]IPoIBMode{
+	"datagram":  IPOIB_MODE_DATAGRAM,
+	"connected": IPOIB_MODE_CONNECTED,
+}
+
+type IPoIB struct {
+	LinkAttrs
+	Pkey   uint16
+	Mode   IPoIBMode
+	Umcast uint16
+}
+
+func (ipoib *IPoIB) Attrs() *LinkAttrs {
+	return &ipoib.LinkAttrs
+}
+
+func (ipoib *IPoIB) Type() string {
+	return "ipoib"
+}
+
 // iproute2 supported devices;
 // vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
 // bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |
-// gre | gretap | ip6gre | ip6gretap | vti | nlmon |
-// bond_slave | ipvlan
+// gre | gretap | ip6gre | ip6gretap | vti | vti6 | nlmon |
+// bond_slave | ipvlan | xfrm
 
 // LinkNotFoundError wraps the various not found errors when
 // getting/reading links. This is intended for better error

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 468 - 115
vendor/github.com/vishvananda/netlink/link_linux.go


+ 7 - 0
vendor/github.com/vishvananda/netlink/neigh.go

@@ -17,9 +17,16 @@ type Neigh struct {
 	LLIPAddr     net.IP //Used in the case of NHRP
 	Vlan         int
 	VNI          int
+	MasterIndex  int
 }
 
 // String returns $ip/$hwaddr $label
 func (neigh *Neigh) String() string {
 	return fmt.Sprintf("%s %s", neigh.IP, neigh.HardwareAddr)
 }
+
+// NeighUpdate is sent when a neighbor changes - type is RTM_NEWNEIGH or RTM_DELNEIGH.
+type NeighUpdate struct {
+	Type uint16
+	Neigh
+}

+ 161 - 28
vendor/github.com/vishvananda/netlink/neigh_linux.go

@@ -1,10 +1,13 @@
 package netlink
 
 import (
+	"fmt"
 	"net"
+	"syscall"
 	"unsafe"
 
 	"github.com/vishvananda/netlink/nl"
+	"github.com/vishvananda/netns"
 	"golang.org/x/sys/unix"
 )
 
@@ -18,7 +21,10 @@ const (
 	NDA_PORT
 	NDA_VNI
 	NDA_IFINDEX
-	NDA_MAX = NDA_IFINDEX
+	NDA_MASTER
+	NDA_LINK_NETNSID
+	NDA_SRC_VNI
+	NDA_MAX = NDA_SRC_VNI
 )
 
 // Neighbor Cache Entry States.
@@ -43,6 +49,7 @@ const (
 	NTF_ROUTER = 0x80
 )
 
+// Ndmsg is for adding, removing or receiving information about a neighbor table entry
 type Ndmsg struct {
 	Family uint8
 	Index  uint32
@@ -170,45 +177,58 @@ func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
 		req.AddData(vniData)
 	}
 
+	if neigh.MasterIndex != 0 {
+		masterData := nl.NewRtAttr(NDA_MASTER, nl.Uint32Attr(uint32(neigh.MasterIndex)))
+		req.AddData(masterData)
+	}
+
 	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
 	return err
 }
 
-// NeighList gets a list of IP-MAC mappings in the system (ARP table).
+// NeighList returns a list of IP-MAC mappings in the system (ARP table).
 // Equivalent to: `ip neighbor show`.
 // The list can be filtered by link and ip family.
 func NeighList(linkIndex, family int) ([]Neigh, error) {
 	return pkgHandle.NeighList(linkIndex, family)
 }
 
-// NeighProxyList gets a list of neighbor proxies in the system.
+// NeighProxyList returns a list of neighbor proxies in the system.
 // Equivalent to: `ip neighbor show proxy`.
 // The list can be filtered by link and ip family.
 func NeighProxyList(linkIndex, family int) ([]Neigh, error) {
 	return pkgHandle.NeighProxyList(linkIndex, family)
 }
 
-// NeighList gets a list of IP-MAC mappings in the system (ARP table).
+// NeighList returns a list of IP-MAC mappings in the system (ARP table).
 // Equivalent to: `ip neighbor show`.
 // The list can be filtered by link and ip family.
 func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
-	return h.neighList(linkIndex, family, 0)
+	return h.NeighListExecute(Ndmsg{
+		Family: uint8(family),
+		Index:  uint32(linkIndex),
+	})
 }
 
-// NeighProxyList gets a list of neighbor proxies in the system.
+// NeighProxyList returns a list of neighbor proxies in the system.
 // Equivalent to: `ip neighbor show proxy`.
 // The list can be filtered by link, ip family.
 func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
-	return h.neighList(linkIndex, family, NTF_PROXY)
+	return h.NeighListExecute(Ndmsg{
+		Family: uint8(family),
+		Index:  uint32(linkIndex),
+		Flags:  NTF_PROXY,
+	})
+}
+
+// NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state.
+func NeighListExecute(msg Ndmsg) ([]Neigh, error) {
+	return pkgHandle.NeighListExecute(msg)
 }
 
-func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) {
+// NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state.
+func (h *Handle) NeighListExecute(msg Ndmsg) ([]Neigh, error) {
 	req := h.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP)
-	msg := Ndmsg{
-		Family: uint8(family),
-		Index:  uint32(linkIndex),
-		Flags:  uint8(flags),
-	}
 	req.AddData(&msg)
 
 	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH)
@@ -219,7 +239,7 @@ func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) {
 	var res []Neigh
 	for _, m := range msgs {
 		ndm := deserializeNdmsg(m)
-		if linkIndex != 0 && int(ndm.Index) != linkIndex {
+		if msg.Index != 0 && ndm.Index != msg.Index {
 			// Ignore messages from other interfaces
 			continue
 		}
@@ -251,14 +271,6 @@ func NeighDeserialize(m []byte) (*Neigh, error) {
 		return nil, err
 	}
 
-	// This should be cached for perfomance
-	// once per table dump
-	link, err := LinkByIndex(neigh.LinkIndex)
-	if err != nil {
-		return nil, err
-	}
-	encapType := link.Attrs().EncapType
-
 	for _, attr := range attrs {
 		switch attr.Attr.Type {
 		case NDA_DST:
@@ -268,13 +280,16 @@ func NeighDeserialize(m []byte) (*Neigh, error) {
 			// #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
 			// #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
 			attrLen := attr.Attr.Len - unix.SizeofRtAttr
-			if attrLen == 4 && (encapType == "ipip" ||
-				encapType == "sit" ||
-				encapType == "gre") {
+			if attrLen == 4 {
 				neigh.LLIPAddr = net.IP(attr.Value)
-			} else if attrLen == 16 &&
-				encapType == "tunnel6" {
-				neigh.IP = net.IP(attr.Value)
+			} else if attrLen == 16 {
+				// Can be IPv6 or FireWire HWAddr
+				link, err := LinkByIndex(neigh.LinkIndex)
+				if err == nil && link.Attrs().EncapType == "tunnel6" {
+					neigh.IP = net.IP(attr.Value)
+				} else {
+					neigh.HardwareAddr = net.HardwareAddr(attr.Value)
+				}
 			} else {
 				neigh.HardwareAddr = net.HardwareAddr(attr.Value)
 			}
@@ -282,8 +297,126 @@ func NeighDeserialize(m []byte) (*Neigh, error) {
 			neigh.Vlan = int(native.Uint16(attr.Value[0:2]))
 		case NDA_VNI:
 			neigh.VNI = int(native.Uint32(attr.Value[0:4]))
+		case NDA_MASTER:
+			neigh.MasterIndex = int(native.Uint32(attr.Value[0:4]))
 		}
 	}
 
 	return &neigh, nil
 }
+
+// NeighSubscribe takes a chan down which notifications will be sent
+// when neighbors are added or deleted. Close the 'done' chan to stop subscription.
+func NeighSubscribe(ch chan<- NeighUpdate, done <-chan struct{}) error {
+	return neighSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
+}
+
+// NeighSubscribeAt works like NeighSubscribe plus it allows the caller
+// to choose the network namespace in which to subscribe (ns).
+func NeighSubscribeAt(ns netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}) error {
+	return neighSubscribeAt(ns, netns.None(), ch, done, nil, false)
+}
+
+// NeighSubscribeOptions contains a set of options to use with
+// NeighSubscribeWithOptions.
+type NeighSubscribeOptions struct {
+	Namespace     *netns.NsHandle
+	ErrorCallback func(error)
+	ListExisting  bool
+}
+
+// NeighSubscribeWithOptions work like NeighSubscribe but enable to
+// provide additional options to modify the behavior. Currently, the
+// namespace can be provided as well as an error callback.
+func NeighSubscribeWithOptions(ch chan<- NeighUpdate, done <-chan struct{}, options NeighSubscribeOptions) error {
+	if options.Namespace == nil {
+		none := netns.None()
+		options.Namespace = &none
+	}
+	return neighSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
+}
+
+func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
+	s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_NEIGH)
+	makeRequest := func(family int) error {
+		req := pkgHandle.newNetlinkRequest(unix.RTM_GETNEIGH,
+			unix.NLM_F_DUMP)
+		infmsg := nl.NewIfInfomsg(family)
+		req.AddData(infmsg)
+		if err := s.Send(req); err != nil {
+			return err
+		}
+		return nil
+	}
+	if err != nil {
+		return err
+	}
+	if done != nil {
+		go func() {
+			<-done
+			s.Close()
+		}()
+	}
+	if listExisting {
+		if err := makeRequest(unix.AF_UNSPEC); err != nil {
+			return err
+		}
+		// We have to wait for NLMSG_DONE before making AF_BRIDGE request
+	}
+	go func() {
+		defer close(ch)
+		for {
+			msgs, from, err := s.Receive()
+			if err != nil {
+				if cberr != nil {
+					cberr(err)
+				}
+				return
+			}
+			if from.Pid != nl.PidKernel {
+				if cberr != nil {
+					cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel))
+				}
+				continue
+			}
+			for _, m := range msgs {
+				if m.Header.Type == unix.NLMSG_DONE {
+					if listExisting {
+						// This will be called after handling AF_UNSPEC
+						// list request, we have to wait for NLMSG_DONE
+						// before making another request
+						if err := makeRequest(unix.AF_BRIDGE); err != nil {
+							if cberr != nil {
+								cberr(err)
+							}
+							return
+						}
+						listExisting = false
+					}
+					continue
+				}
+				if m.Header.Type == unix.NLMSG_ERROR {
+					native := nl.NativeEndian()
+					error := int32(native.Uint32(m.Data[0:4]))
+					if error == 0 {
+						continue
+					}
+					if cberr != nil {
+						cberr(syscall.Errno(-error))
+					}
+					return
+				}
+				neigh, err := NeighDeserialize(m.Data)
+				if err != nil {
+					if cberr != nil {
+						cberr(err)
+					}
+					return
+				}
+				ch <- NeighUpdate{Type: m.Header.Type, Neigh: *neigh}
+			}
+		}
+	}()
+
+	return nil
+}

+ 2 - 1
vendor/github.com/vishvananda/netlink/netlink.go

@@ -27,7 +27,8 @@ func ParseIPNet(s string) (*net.IPNet, error) {
 	if err != nil {
 		return nil, err
 	}
-	return &net.IPNet{IP: ip, Mask: ipNet.Mask}, nil
+	ipNet.IP = ip
+	return ipNet, nil
 }
 
 // NewIPNet generates an IPNet from an ip address using a netmask of 32 or 128.

+ 12 - 0
vendor/github.com/vishvananda/netlink/netlink_unspecified.go

@@ -48,10 +48,18 @@ func LinkSetVfVlan(link Link, vf, vlan int) error {
 	return ErrNotImplemented
 }
 
+func LinkSetVfVlanQos(link Link, vf, vlan, qos int) error {
+	return ErrNotImplemented
+}
+
 func LinkSetVfTxRate(link Link, vf, rate int) error {
 	return ErrNotImplemented
 }
 
+func LinkSetVfRate(link Link, vf, minRate, maxRate int) error {
+	return ErrNotImplemented
+}
+
 func LinkSetNoMaster(link Link) error {
 	return ErrNotImplemented
 }
@@ -152,6 +160,10 @@ func AddrAdd(link Link, addr *Addr) error {
 	return ErrNotImplemented
 }
 
+func AddrReplace(link Link, addr *Addr) error {
+	return ErrNotImplemented
+}
+
 func AddrDel(link Link, addr *Addr) error {
 	return ErrNotImplemented
 }

+ 141 - 0
vendor/github.com/vishvananda/netlink/netns_linux.go

@@ -0,0 +1,141 @@
+package netlink
+
+// Network namespace ID functions
+//
+// The kernel has a weird concept called the network namespace ID.
+// This is different from the file reference in proc (and any bind-mounted
+// namespaces, etc.)
+//
+// Instead, namespaces can be assigned a numeric ID at any time. Once set,
+// the ID is fixed. The ID can either be set manually by the user, or
+// automatically, triggered by certain kernel actions. The most common kernel
+// action that triggers namespace ID creation is moving one end of a veth pair
+// in to that namespace.
+
+import (
+	"fmt"
+
+	"github.com/vishvananda/netlink/nl"
+	"golang.org/x/sys/unix"
+)
+
+// These can be replaced by the values from sys/unix when it is next released.
+const (
+	_ = iota
+	NETNSA_NSID
+	NETNSA_PID
+	NETNSA_FD
+)
+
+// GetNetNsIdByPid looks up the network namespace ID for a given pid (really thread id).
+// Returns -1 if the namespace does not have an ID set.
+func (h *Handle) GetNetNsIdByPid(pid int) (int, error) {
+	return h.getNetNsId(NETNSA_PID, uint32(pid))
+}
+
+// GetNetNsIdByPid looks up the network namespace ID for a given pid (really thread id).
+// Returns -1 if the namespace does not have an ID set.
+func GetNetNsIdByPid(pid int) (int, error) {
+	return pkgHandle.GetNetNsIdByPid(pid)
+}
+
+// SetNetNSIdByPid sets the ID of the network namespace for a given pid (really thread id).
+// The ID can only be set for namespaces without an ID already set.
+func (h *Handle) SetNetNsIdByPid(pid, nsid int) error {
+	return h.setNetNsId(NETNSA_PID, uint32(pid), uint32(nsid))
+}
+
+// SetNetNSIdByPid sets the ID of the network namespace for a given pid (really thread id).
+// The ID can only be set for namespaces without an ID already set.
+func SetNetNsIdByPid(pid, nsid int) error {
+	return pkgHandle.SetNetNsIdByPid(pid, nsid)
+}
+
+// GetNetNsIdByFd looks up the network namespace ID for a given fd.
+// fd must be an open file descriptor to a namespace file.
+// Returns -1 if the namespace does not have an ID set.
+func (h *Handle) GetNetNsIdByFd(fd int) (int, error) {
+	return h.getNetNsId(NETNSA_FD, uint32(fd))
+}
+
+// GetNetNsIdByFd looks up the network namespace ID for a given fd.
+// fd must be an open file descriptor to a namespace file.
+// Returns -1 if the namespace does not have an ID set.
+func GetNetNsIdByFd(fd int) (int, error) {
+	return pkgHandle.GetNetNsIdByFd(fd)
+}
+
+// SetNetNSIdByFd sets the ID of the network namespace for a given fd.
+// fd must be an open file descriptor to a namespace file.
+// The ID can only be set for namespaces without an ID already set.
+func (h *Handle) SetNetNsIdByFd(fd, nsid int) error {
+	return h.setNetNsId(NETNSA_FD, uint32(fd), uint32(nsid))
+}
+
+// SetNetNSIdByFd sets the ID of the network namespace for a given fd.
+// fd must be an open file descriptor to a namespace file.
+// The ID can only be set for namespaces without an ID already set.
+func SetNetNsIdByFd(fd, nsid int) error {
+	return pkgHandle.SetNetNsIdByFd(fd, nsid)
+}
+
+// getNetNsId requests the netnsid for a given type-val pair
+// type should be either NETNSA_PID or NETNSA_FD
+func (h *Handle) getNetNsId(attrType int, val uint32) (int, error) {
+	req := h.newNetlinkRequest(unix.RTM_GETNSID, unix.NLM_F_REQUEST)
+
+	rtgen := nl.NewRtGenMsg()
+	req.AddData(rtgen)
+
+	b := make([]byte, 4, 4)
+	native.PutUint32(b, val)
+	attr := nl.NewRtAttr(attrType, b)
+	req.AddData(attr)
+
+	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNSID)
+
+	if err != nil {
+		return 0, err
+	}
+
+	for _, m := range msgs {
+		msg := nl.DeserializeRtGenMsg(m)
+
+		attrs, err := nl.ParseRouteAttr(m[msg.Len():])
+		if err != nil {
+			return 0, err
+		}
+
+		for _, attr := range attrs {
+			switch attr.Attr.Type {
+			case NETNSA_NSID:
+				return int(int32(native.Uint32(attr.Value))), nil
+			}
+		}
+	}
+
+	return 0, fmt.Errorf("unexpected empty result")
+}
+
+// setNetNsId sets the netnsid for a given type-val pair
+// type should be either NETNSA_PID or NETNSA_FD
+// The ID can only be set for namespaces without an ID already set
+func (h *Handle) setNetNsId(attrType int, val uint32, newnsid uint32) error {
+	req := h.newNetlinkRequest(unix.RTM_NEWNSID, unix.NLM_F_REQUEST|unix.NLM_F_ACK)
+
+	rtgen := nl.NewRtGenMsg()
+	req.AddData(rtgen)
+
+	b := make([]byte, 4, 4)
+	native.PutUint32(b, val)
+	attr := nl.NewRtAttr(attrType, b)
+	req.AddData(attr)
+
+	b1 := make([]byte, 4, 4)
+	native.PutUint32(b1, newnsid)
+	attr1 := nl.NewRtAttr(NETNSA_NSID, b1)
+	req.AddData(attr1)
+
+	_, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNSID)
+	return err
+}

+ 19 - 0
vendor/github.com/vishvananda/netlink/netns_unspecified.go

@@ -0,0 +1,19 @@
+// +build !linux
+
+package netlink
+
+func GetNetNsIdByPid(pid int) (int, error) {
+	return 0, ErrNotImplemented
+}
+
+func SetNetNsIdByPid(pid, nsid int) error {
+	return ErrNotImplemented
+}
+
+func GetNetNsIdByFd(fd int) (int, error) {
+	return 0, ErrNotImplemented
+}
+
+func SetNetNsIdByFd(fd, nsid int) error {
+	return ErrNotImplemented
+}

+ 2 - 2
vendor/github.com/vishvananda/netlink/nl/bridge_linux.go

@@ -11,8 +11,8 @@ const (
 
 /* Bridge Flags */
 const (
-	BRIDGE_FLAGS_MASTER = iota /* Bridge command to/from master */
-	BRIDGE_FLAGS_SELF          /* Bridge command to/from lowerdev */
+	BRIDGE_FLAGS_MASTER = iota + 1 /* Bridge command to/from master */
+	BRIDGE_FLAGS_SELF              /* Bridge command to/from lowerdev */
 )
 
 /* Bridge management nested attributes

+ 34 - 6
vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go

@@ -76,12 +76,17 @@ const (
 // 	__CTA_MAX
 // };
 const (
-	CTA_TUPLE_ORIG  = 1
-	CTA_TUPLE_REPLY = 2
-	CTA_STATUS      = 3
-	CTA_TIMEOUT     = 7
-	CTA_MARK        = 8
-	CTA_PROTOINFO   = 4
+	CTA_TUPLE_ORIG     = 1
+	CTA_TUPLE_REPLY    = 2
+	CTA_STATUS         = 3
+	CTA_PROTOINFO      = 4
+	CTA_TIMEOUT        = 7
+	CTA_MARK           = 8
+	CTA_COUNTERS_ORIG  = 9
+	CTA_COUNTERS_REPLY = 10
+	CTA_USE            = 11
+	CTA_ID             = 12
+	CTA_TIMESTAMP      = 20
 )
 
 // enum ctattr_tuple {
@@ -163,6 +168,29 @@ const (
 	CTA_PROTOINFO_TCP_FLAGS_REPLY     = 5
 )
 
+// enum ctattr_counters {
+// 	CTA_COUNTERS_UNSPEC,
+// 	CTA_COUNTERS_PACKETS,		/* 64bit counters */
+// 	CTA_COUNTERS_BYTES,		/* 64bit counters */
+// 	CTA_COUNTERS32_PACKETS,		/* old 32bit counters, unused */
+// 	CTA_COUNTERS32_BYTES,		/* old 32bit counters, unused */
+// 	CTA_COUNTERS_PAD,
+// 	__CTA_COUNTERS_M
+// };
+// #define CTA_COUNTERS_MAX (__CTA_COUNTERS_MAX - 1)
+const (
+	CTA_COUNTERS_PACKETS = 1
+	CTA_COUNTERS_BYTES   = 2
+)
+
+// enum CTA TIMESTAMP TLVs
+// CTA_TIMESTAMP_START       /* 64bit value */
+// CTA_TIMESTAMP_STOP        /* 64bit value */
+const (
+	CTA_TIMESTAMP_START = 1
+	CTA_TIMESTAMP_STOP  = 2
+)
+
 // /* General form of address family dependent message.
 //  */
 // struct nfgenmsg {

+ 40 - 0
vendor/github.com/vishvananda/netlink/nl/devlink_linux.go

@@ -0,0 +1,40 @@
+package nl
+
+// All the following constants are coming from:
+// https://github.com/torvalds/linux/blob/master/include/uapi/linux/devlink.h
+
+const (
+	GENL_DEVLINK_VERSION = 1
+	GENL_DEVLINK_NAME    = "devlink"
+)
+
+const (
+	DEVLINK_CMD_GET         = 1
+	DEVLINK_CMD_ESWITCH_GET = 29
+	DEVLINK_CMD_ESWITCH_SET = 30
+)
+
+const (
+	DEVLINK_ATTR_BUS_NAME            = 1
+	DEVLINK_ATTR_DEV_NAME            = 2
+	DEVLINK_ATTR_ESWITCH_MODE        = 25
+	DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26
+	DEVLINK_ATTR_ESWITCH_ENCAP_MODE  = 62
+)
+
+const (
+	DEVLINK_ESWITCH_MODE_LEGACY    = 0
+	DEVLINK_ESWITCH_MODE_SWITCHDEV = 1
+)
+
+const (
+	DEVLINK_ESWITCH_INLINE_MODE_NONE      = 0
+	DEVLINK_ESWITCH_INLINE_MODE_LINK      = 1
+	DEVLINK_ESWITCH_INLINE_MODE_NETWORK   = 2
+	DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT = 3
+)
+
+const (
+	DEVLINK_ESWITCH_ENCAP_MODE_NONE  = 0
+	DEVLINK_ESWITCH_ENCAP_MODE_BASIC = 1
+)

+ 67 - 5
vendor/github.com/vishvananda/netlink/nl/link_linux.go

@@ -13,7 +13,9 @@ const (
 	IFLA_INFO_KIND
 	IFLA_INFO_DATA
 	IFLA_INFO_XSTATS
-	IFLA_INFO_MAX = IFLA_INFO_XSTATS
+	IFLA_INFO_SLAVE_KIND
+	IFLA_INFO_SLAVE_DATA
+	IFLA_INFO_MAX = IFLA_INFO_SLAVE_DATA
 )
 
 const (
@@ -87,7 +89,8 @@ const (
 const (
 	IFLA_IPVLAN_UNSPEC = iota
 	IFLA_IPVLAN_MODE
-	IFLA_IPVLAN_MAX = IFLA_IPVLAN_MODE
+	IFLA_IPVLAN_FLAG
+	IFLA_IPVLAN_MAX = IFLA_IPVLAN_FLAG
 )
 
 const (
@@ -164,6 +167,8 @@ const (
 	IFLA_BOND_SLAVE_PERM_HWADDR
 	IFLA_BOND_SLAVE_QUEUE_ID
 	IFLA_BOND_SLAVE_AD_AGGREGATOR_ID
+	IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE
+	IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE
 )
 
 const (
@@ -217,9 +222,11 @@ const (
 	IFLA_VF_RSS_QUERY_EN /* RSS Redirection Table and Hash Key query
 	 * on/off switch
 	 */
-	IFLA_VF_STATS /* network device statistics */
-	IFLA_VF_TRUST /* Trust state of VF */
-	IFLA_VF_MAX   = IFLA_VF_TRUST
+	IFLA_VF_STATS        /* network device statistics */
+	IFLA_VF_TRUST        /* Trust state of VF */
+	IFLA_VF_IB_NODE_GUID /* VF Infiniband node GUID */
+	IFLA_VF_IB_PORT_GUID /* VF Infiniband port GUID */
+	IFLA_VF_MAX          = IFLA_VF_IB_PORT_GUID
 )
 
 const (
@@ -248,6 +255,7 @@ const (
 	SizeofVfLinkState  = 0x08
 	SizeofVfRssQueryEn = 0x08
 	SizeofVfTrust      = 0x08
+	SizeofVfGUID       = 0x10
 )
 
 // struct ifla_vf_mac {
@@ -430,6 +438,30 @@ func (msg *VfTrust) Serialize() []byte {
 	return (*(*[SizeofVfTrust]byte)(unsafe.Pointer(msg)))[:]
 }
 
+// struct ifla_vf_guid {
+//   __u32 vf;
+//   __u32 rsvd;
+//   __u64 guid;
+// };
+
+type VfGUID struct {
+	Vf   uint32
+	Rsvd uint32
+	GUID uint64
+}
+
+func (msg *VfGUID) Len() int {
+	return SizeofVfGUID
+}
+
+func DeserializeVfGUID(b []byte) *VfGUID {
+	return (*VfGUID)(unsafe.Pointer(&b[0:SizeofVfGUID][0]))
+}
+
+func (msg *VfGUID) Serialize() []byte {
+	return (*(*[SizeofVfGUID]byte)(unsafe.Pointer(msg)))[:]
+}
+
 const (
 	XDP_FLAGS_UPDATE_IF_NOEXIST = 1 << iota
 	XDP_FLAGS_SKB_MODE
@@ -546,3 +578,33 @@ const (
 	GTP_ROLE_GGSN = iota
 	GTP_ROLE_SGSN
 )
+
+const (
+	IFLA_XFRM_UNSPEC = iota
+	IFLA_XFRM_LINK
+	IFLA_XFRM_IF_ID
+
+	IFLA_XFRM_MAX = iota - 1
+)
+
+const (
+	IFLA_TUN_UNSPEC = iota
+	IFLA_TUN_OWNER
+	IFLA_TUN_GROUP
+	IFLA_TUN_TYPE
+	IFLA_TUN_PI
+	IFLA_TUN_VNET_HDR
+	IFLA_TUN_PERSIST
+	IFLA_TUN_MULTI_QUEUE
+	IFLA_TUN_NUM_QUEUES
+	IFLA_TUN_NUM_DISABLED_QUEUES
+	IFLA_TUN_MAX = IFLA_TUN_NUM_DISABLED_QUEUES
+)
+
+const (
+	IFLA_IPOIB_UNSPEC = iota
+	IFLA_IPOIB_PKEY
+	IFLA_IPOIB_MODE
+	IFLA_IPOIB_UMCAST
+	IFLA_IPOIB_MAX = IFLA_IPOIB_UMCAST
+)

+ 44 - 22
vendor/github.com/vishvananda/netlink/nl/nl_linux.go

@@ -21,7 +21,13 @@ const (
 	FAMILY_ALL  = unix.AF_UNSPEC
 	FAMILY_V4   = unix.AF_INET
 	FAMILY_V6   = unix.AF_INET6
-	FAMILY_MPLS = AF_MPLS
+	FAMILY_MPLS = unix.AF_MPLS
+	// Arbitrary set value (greater than default 4k) to allow receiving
+	// from kernel more verbose messages e.g. for statistics,
+	// tc rules or filters, or other more memory requiring data.
+	RECEIVE_BUFFER_SIZE = 65536
+	// Kernel netlink pid
+	PidKernel uint32 = 0
 )
 
 // SupportedNlFamilies contains the list of netlink families this netlink package supports
@@ -42,7 +48,7 @@ func GetIPFamily(ip net.IP) int {
 
 var nativeEndian binary.ByteOrder
 
-// Get native endianness for the system
+// NativeEndian gets native endianness for the system
 func NativeEndian() binary.ByteOrder {
 	if nativeEndian == nil {
 		var x uint32 = 0x01020304
@@ -271,15 +277,22 @@ func NewRtAttr(attrType int, data []byte) *RtAttr {
 	}
 }
 
-// Create a new RtAttr obj anc add it as a child of an existing object
+// NewRtAttrChild adds an RtAttr as a child to the parent and returns the new attribute
+//
+// Deprecated: Use AddRtAttr() on the parent object
 func NewRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr {
+	return parent.AddRtAttr(attrType, data)
+}
+
+// AddRtAttr adds an RtAttr as a child and returns the new attribute
+func (a *RtAttr) AddRtAttr(attrType int, data []byte) *RtAttr {
 	attr := NewRtAttr(attrType, data)
-	parent.children = append(parent.children, attr)
+	a.children = append(a.children, attr)
 	return attr
 }
 
-// AddChild adds an existing RtAttr as a child.
-func (a *RtAttr) AddChild(attr *RtAttr) {
+// AddChild adds an existing NetlinkRequestData as a child.
+func (a *RtAttr) AddChild(attr NetlinkRequestData) {
 	a.children = append(a.children, attr)
 }
 
@@ -360,16 +373,12 @@ func (req *NetlinkRequest) Serialize() []byte {
 }
 
 func (req *NetlinkRequest) AddData(data NetlinkRequestData) {
-	if data != nil {
-		req.Data = append(req.Data, data)
-	}
+	req.Data = append(req.Data, data)
 }
 
 // AddRawData adds raw bytes to the end of the NetlinkRequest object during serialization
 func (req *NetlinkRequest) AddRawData(data []byte) {
-	if data != nil {
-		req.RawData = append(req.RawData, data...)
-	}
+	req.RawData = append(req.RawData, data...)
 }
 
 // Execute the request against a the given sockType.
@@ -413,10 +422,13 @@ func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, erro
 
 done:
 	for {
-		msgs, err := s.Receive()
+		msgs, from, err := s.Receive()
 		if err != nil {
 			return nil, err
 		}
+		if from.Pid != PidKernel {
+			return nil, fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, PidKernel)
+		}
 		for _, m := range msgs {
 			if m.Header.Seq != req.Seq {
 				if sharedSocket {
@@ -425,7 +437,7 @@ done:
 				return nil, fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, req.Seq)
 			}
 			if m.Header.Pid != pid {
-				return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
+				continue
 			}
 			if m.Header.Type == unix.NLMSG_DONE {
 				break done
@@ -610,21 +622,31 @@ func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
 	return nil
 }
 
-func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
+func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, *unix.SockaddrNetlink, error) {
 	fd := int(atomic.LoadInt32(&s.fd))
 	if fd < 0 {
-		return nil, fmt.Errorf("Receive called on a closed socket")
+		return nil, nil, fmt.Errorf("Receive called on a closed socket")
 	}
-	rb := make([]byte, unix.Getpagesize())
-	nr, _, err := unix.Recvfrom(fd, rb, 0)
+	var fromAddr *unix.SockaddrNetlink
+	var rb [RECEIVE_BUFFER_SIZE]byte
+	nr, from, err := unix.Recvfrom(fd, rb[:], 0)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
+	}
+	fromAddr, ok := from.(*unix.SockaddrNetlink)
+	if !ok {
+		return nil, nil, fmt.Errorf("Error converting to netlink sockaddr")
 	}
 	if nr < unix.NLMSG_HDRLEN {
-		return nil, fmt.Errorf("Got short response from netlink")
+		return nil, nil, fmt.Errorf("Got short response from netlink")
+	}
+	rb2 := make([]byte, nr)
+	copy(rb2, rb[:nr])
+	nl, err := syscall.ParseNetlinkMessage(rb2)
+	if err != nil {
+		return nil, nil, err
 	}
-	rb = rb[:nr]
-	return syscall.ParseNetlinkMessage(rb)
+	return nl, fromAddr, nil
 }
 
 // SetSendTimeout allows to set a send timeout on the socket

+ 35 - 0
vendor/github.com/vishvananda/netlink/nl/rdma_link_linux.go

@@ -0,0 +1,35 @@
+package nl
+
+const (
+	RDMA_NL_GET_CLIENT_SHIFT = 10
+)
+
+const (
+	RDMA_NL_NLDEV = 5
+)
+
+const (
+	RDMA_NLDEV_CMD_GET     = 1
+	RDMA_NLDEV_CMD_SET     = 2
+	RDMA_NLDEV_CMD_SYS_GET = 6
+	RDMA_NLDEV_CMD_SYS_SET = 7
+)
+
+const (
+	RDMA_NLDEV_ATTR_DEV_INDEX       = 1
+	RDMA_NLDEV_ATTR_DEV_NAME        = 2
+	RDMA_NLDEV_ATTR_PORT_INDEX      = 3
+	RDMA_NLDEV_ATTR_CAP_FLAGS       = 4
+	RDMA_NLDEV_ATTR_FW_VERSION      = 5
+	RDMA_NLDEV_ATTR_NODE_GUID       = 6
+	RDMA_NLDEV_ATTR_SYS_IMAGE_GUID  = 7
+	RDMA_NLDEV_ATTR_SUBNET_PREFIX   = 8
+	RDMA_NLDEV_ATTR_LID             = 9
+	RDMA_NLDEV_ATTR_SM_LID          = 10
+	RDMA_NLDEV_ATTR_LMC             = 11
+	RDMA_NLDEV_ATTR_PORT_STATE      = 12
+	RDMA_NLDEV_ATTR_PORT_PHYS_STATE = 13
+	RDMA_NLDEV_ATTR_DEV_NODE_TYPE   = 14
+	RDMA_NLDEV_SYS_ATTR_NETNS_MODE  = 66
+	RDMA_NLDEV_NET_NS_FD            = 68
+)

+ 26 - 0
vendor/github.com/vishvananda/netlink/nl/route_linux.go

@@ -79,3 +79,29 @@ func (msg *RtNexthop) Serialize() []byte {
 	}
 	return buf
 }
+
+type RtGenMsg struct {
+	unix.RtGenmsg
+}
+
+func NewRtGenMsg() *RtGenMsg {
+	return &RtGenMsg{
+		RtGenmsg: unix.RtGenmsg{
+			Family: unix.AF_UNSPEC,
+		},
+	}
+}
+
+func (msg *RtGenMsg) Len() int {
+	return rtaAlignOf(unix.SizeofRtGenmsg)
+}
+
+func DeserializeRtGenMsg(b []byte) *RtGenMsg {
+	return &RtGenMsg{RtGenmsg: unix.RtGenmsg{Family: b[0]}}
+}
+
+func (msg *RtGenMsg) Serialize() []byte {
+	out := make([]byte, msg.Len())
+	out[0] = msg.Family
+	return out
+}

+ 43 - 0
vendor/github.com/vishvananda/netlink/nl/seg6_linux.go

@@ -99,6 +99,49 @@ func DecodeSEG6Encap(buf []byte) (int, []net.IP, error) {
 	return mode, srh.Segments, nil
 }
 
+func DecodeSEG6Srh(buf []byte) ([]net.IP, error) {
+	native := NativeEndian()
+	srh := IPv6SrHdr{
+		nextHdr:      buf[0],
+		hdrLen:       buf[1],
+		routingType:  buf[2],
+		segmentsLeft: buf[3],
+		firstSegment: buf[4],
+		flags:        buf[5],
+		reserved:     native.Uint16(buf[6:8]),
+	}
+	buf = buf[8:]
+	if len(buf)%16 != 0 {
+		err := fmt.Errorf("DecodeSEG6Srh: error parsing Segment List (buf len: %d)", len(buf))
+		return nil, err
+	}
+	for len(buf) > 0 {
+		srh.Segments = append(srh.Segments, net.IP(buf[:16]))
+		buf = buf[16:]
+	}
+	return srh.Segments, nil
+}
+func EncodeSEG6Srh(segments []net.IP) ([]byte, error) {
+	nsegs := len(segments) // nsegs: number of segments
+	if nsegs == 0 {
+		return nil, errors.New("EncodeSEG6Srh: No Segments")
+	}
+	b := make([]byte, 8, 8+len(segments)*16)
+	native := NativeEndian()
+	b[0] = 0                      // srh.nextHdr (0 when calling netlink)
+	b[1] = uint8(16 * nsegs >> 3) // srh.hdrLen (in 8-octets unit)
+	b[2] = IPV6_SRCRT_TYPE_4      // srh.routingType (assigned by IANA)
+	b[3] = uint8(nsegs - 1)       // srh.segmentsLeft
+	b[4] = uint8(nsegs - 1)       // srh.firstSegment
+	b[5] = 0                      // srh.flags (SR6_FLAG1_HMAC for srh_hmac)
+	// srh.reserved: Defined as "Tag" in draft-ietf-6man-segment-routing-header-07
+	native.PutUint16(b[6:], 0) // srh.reserved
+	for _, netIP := range segments {
+		b = append(b, netIP...) // srh.Segments
+	}
+	return b, nil
+}
+
 // Helper functions
 func SEG6EncapModeString(mode int) string {
 	switch mode {

+ 76 - 0
vendor/github.com/vishvananda/netlink/nl/seg6local_linux.go

@@ -0,0 +1,76 @@
+package nl
+
+import ()
+
+// seg6local parameters
+const (
+	SEG6_LOCAL_UNSPEC = iota
+	SEG6_LOCAL_ACTION
+	SEG6_LOCAL_SRH
+	SEG6_LOCAL_TABLE
+	SEG6_LOCAL_NH4
+	SEG6_LOCAL_NH6
+	SEG6_LOCAL_IIF
+	SEG6_LOCAL_OIF
+	__SEG6_LOCAL_MAX
+)
+const (
+	SEG6_LOCAL_MAX = __SEG6_LOCAL_MAX
+)
+
+// seg6local actions
+const (
+	SEG6_LOCAL_ACTION_END           = iota + 1 // 1
+	SEG6_LOCAL_ACTION_END_X                    // 2
+	SEG6_LOCAL_ACTION_END_T                    // 3
+	SEG6_LOCAL_ACTION_END_DX2                  // 4
+	SEG6_LOCAL_ACTION_END_DX6                  // 5
+	SEG6_LOCAL_ACTION_END_DX4                  // 6
+	SEG6_LOCAL_ACTION_END_DT6                  // 7
+	SEG6_LOCAL_ACTION_END_DT4                  // 8
+	SEG6_LOCAL_ACTION_END_B6                   // 9
+	SEG6_LOCAL_ACTION_END_B6_ENCAPS            // 10
+	SEG6_LOCAL_ACTION_END_BM                   // 11
+	SEG6_LOCAL_ACTION_END_S                    // 12
+	SEG6_LOCAL_ACTION_END_AS                   // 13
+	SEG6_LOCAL_ACTION_END_AM                   // 14
+	__SEG6_LOCAL_ACTION_MAX
+)
+const (
+	SEG6_LOCAL_ACTION_MAX = __SEG6_LOCAL_ACTION_MAX - 1
+)
+
+// Helper functions
+func SEG6LocalActionString(action int) string {
+	switch action {
+	case SEG6_LOCAL_ACTION_END:
+		return "End"
+	case SEG6_LOCAL_ACTION_END_X:
+		return "End.X"
+	case SEG6_LOCAL_ACTION_END_T:
+		return "End.T"
+	case SEG6_LOCAL_ACTION_END_DX2:
+		return "End.DX2"
+	case SEG6_LOCAL_ACTION_END_DX6:
+		return "End.DX6"
+	case SEG6_LOCAL_ACTION_END_DX4:
+		return "End.DX4"
+	case SEG6_LOCAL_ACTION_END_DT6:
+		return "End.DT6"
+	case SEG6_LOCAL_ACTION_END_DT4:
+		return "End.DT4"
+	case SEG6_LOCAL_ACTION_END_B6:
+		return "End.B6"
+	case SEG6_LOCAL_ACTION_END_B6_ENCAPS:
+		return "End.B6.Encaps"
+	case SEG6_LOCAL_ACTION_END_BM:
+		return "End.BM"
+	case SEG6_LOCAL_ACTION_END_S:
+		return "End.S"
+	case SEG6_LOCAL_ACTION_END_AS:
+		return "End.AS"
+	case SEG6_LOCAL_ACTION_END_AM:
+		return "End.AM"
+	}
+	return "unknown"
+}

+ 1 - 10
vendor/github.com/vishvananda/netlink/nl/syscall.go

@@ -42,16 +42,6 @@ const (
 	TCPDIAG_NOCOOKIE    = 0xFFFFFFFF /* TCPDIAG_NOCOOKIE in net/ipv4/tcp_diag.h*/
 )
 
-const (
-	AF_MPLS = 28
-)
-
-const (
-	RTA_NEWDST     = 0x13
-	RTA_ENCAP_TYPE = 0x15
-	RTA_ENCAP      = 0x16
-)
-
 // RTA_ENCAP subtype
 const (
 	MPLS_IPTUNNEL_UNSPEC = iota
@@ -67,6 +57,7 @@ const (
 	LWTUNNEL_ENCAP_IP6
 	LWTUNNEL_ENCAP_SEG6
 	LWTUNNEL_ENCAP_BPF
+	LWTUNNEL_ENCAP_SEG6_LOCAL
 )
 
 // routing header types

+ 165 - 1
vendor/github.com/vishvananda/netlink/nl/tc_linux.go

@@ -1,6 +1,7 @@
 package nl
 
 import (
+	"encoding/binary"
 	"unsafe"
 )
 
@@ -64,6 +65,15 @@ const (
 	TCA_PRIO_MAX = TCA_PRIO_MQ
 )
 
+const (
+	TCA_STATS_UNSPEC = iota
+	TCA_STATS_BASIC
+	TCA_STATS_RATE_EST
+	TCA_STATS_QUEUE
+	TCA_STATS_APP
+	TCA_STATS_MAX = TCA_STATS_APP
+)
+
 const (
 	SizeofTcMsg          = 0x14
 	SizeofTcActionMsg    = 0x04
@@ -79,7 +89,10 @@ const (
 	SizeofTcU32Key       = 0x10
 	SizeofTcU32Sel       = 0x10 // without keys
 	SizeofTcGen          = 0x14
+	SizeofTcConnmark     = SizeofTcGen + 0x04
 	SizeofTcMirred       = SizeofTcGen + 0x08
+	SizeofTcTunnelKey    = SizeofTcGen + 0x04
+	SizeofTcSkbEdit      = SizeofTcGen
 	SizeofTcPolice       = 2*SizeofTcRateSpec + 0x20
 )
 
@@ -412,6 +425,57 @@ func (x *TcHtbGlob) Serialize() []byte {
 	return (*(*[SizeofTcHtbGlob]byte)(unsafe.Pointer(x)))[:]
 }
 
+// HFSC
+
+type Curve struct {
+	m1 uint32
+	d  uint32
+	m2 uint32
+}
+
+type HfscCopt struct {
+	Rsc Curve
+	Fsc Curve
+	Usc Curve
+}
+
+func (c *Curve) Attrs() (uint32, uint32, uint32) {
+	return c.m1, c.d, c.m2
+}
+
+func (c *Curve) Set(m1 uint32, d uint32, m2 uint32) {
+	c.m1 = m1
+	c.d = d
+	c.m2 = m2
+}
+
+func DeserializeHfscCurve(b []byte) *Curve {
+	return &Curve{
+		m1: binary.LittleEndian.Uint32(b[0:4]),
+		d:  binary.LittleEndian.Uint32(b[4:8]),
+		m2: binary.LittleEndian.Uint32(b[8:12]),
+	}
+}
+
+func SerializeHfscCurve(c *Curve) (b []byte) {
+	t := make([]byte, binary.MaxVarintLen32)
+	binary.LittleEndian.PutUint32(t, c.m1)
+	b = append(b, t[:4]...)
+	binary.LittleEndian.PutUint32(t, c.d)
+	b = append(b, t[:4]...)
+	binary.LittleEndian.PutUint32(t, c.m2)
+	b = append(b, t[:4]...)
+	return b
+}
+
+type TcHfscOpt struct {
+	Defcls uint16
+}
+
+func (x *TcHfscOpt) Serialize() []byte {
+	return (*(*[2]byte)(unsafe.Pointer(x)))[:]
+}
+
 const (
 	TCA_U32_UNSPEC = iota
 	TCA_U32_CLASSID
@@ -586,11 +650,47 @@ const (
 	TCA_BPF_FD
 	TCA_BPF_NAME
 	TCA_BPF_FLAGS
-	TCA_BPF_MAX = TCA_BPF_FLAGS
+	TCA_BPF_FLAGS_GEN
+	TCA_BPF_TAG
+	TCA_BPF_ID
+	TCA_BPF_MAX = TCA_BPF_ID
 )
 
 type TcBpf TcGen
 
+const (
+	TCA_ACT_CONNMARK = 14
+)
+
+const (
+	TCA_CONNMARK_UNSPEC = iota
+	TCA_CONNMARK_PARMS
+	TCA_CONNMARK_TM
+	TCA_CONNMARK_MAX = TCA_CONNMARK_TM
+)
+
+// struct tc_connmark {
+//   tc_gen;
+//   __u16 zone;
+// };
+
+type TcConnmark struct {
+	TcGen
+	Zone uint16
+}
+
+func (msg *TcConnmark) Len() int {
+	return SizeofTcConnmark
+}
+
+func DeserializeTcConnmark(b []byte) *TcConnmark {
+	return (*TcConnmark)(unsafe.Pointer(&b[0:SizeofTcConnmark][0]))
+}
+
+func (x *TcConnmark) Serialize() []byte {
+	return (*(*[SizeofTcConnmark]byte)(unsafe.Pointer(x)))[:]
+}
+
 const (
 	TCA_ACT_MIRRED = 8
 )
@@ -626,6 +726,63 @@ func (x *TcMirred) Serialize() []byte {
 	return (*(*[SizeofTcMirred]byte)(unsafe.Pointer(x)))[:]
 }
 
+const (
+	TCA_TUNNEL_KEY_UNSPEC = iota
+	TCA_TUNNEL_KEY_TM
+	TCA_TUNNEL_KEY_PARMS
+	TCA_TUNNEL_KEY_ENC_IPV4_SRC
+	TCA_TUNNEL_KEY_ENC_IPV4_DST
+	TCA_TUNNEL_KEY_ENC_IPV6_SRC
+	TCA_TUNNEL_KEY_ENC_IPV6_DST
+	TCA_TUNNEL_KEY_ENC_KEY_ID
+	TCA_TUNNEL_KEY_MAX = TCA_TUNNEL_KEY_ENC_KEY_ID
+)
+
+type TcTunnelKey struct {
+	TcGen
+	Action int32
+}
+
+func (x *TcTunnelKey) Len() int {
+	return SizeofTcTunnelKey
+}
+
+func DeserializeTunnelKey(b []byte) *TcTunnelKey {
+	return (*TcTunnelKey)(unsafe.Pointer(&b[0:SizeofTcTunnelKey][0]))
+}
+
+func (x *TcTunnelKey) Serialize() []byte {
+	return (*(*[SizeofTcTunnelKey]byte)(unsafe.Pointer(x)))[:]
+}
+
+const (
+	TCA_SKBEDIT_UNSPEC = iota
+	TCA_SKBEDIT_TM
+	TCA_SKBEDIT_PARMS
+	TCA_SKBEDIT_PRIORITY
+	TCA_SKBEDIT_QUEUE_MAPPING
+	TCA_SKBEDIT_MARK
+	TCA_SKBEDIT_PAD
+	TCA_SKBEDIT_PTYPE
+	TCA_SKBEDIT_MAX = TCA_SKBEDIT_MARK
+)
+
+type TcSkbEdit struct {
+	TcGen
+}
+
+func (x *TcSkbEdit) Len() int {
+	return SizeofTcSkbEdit
+}
+
+func DeserializeSkbEdit(b []byte) *TcSkbEdit {
+	return (*TcSkbEdit)(unsafe.Pointer(&b[0:SizeofTcSkbEdit][0]))
+}
+
+func (x *TcSkbEdit) Serialize() []byte {
+	return (*(*[SizeofTcSkbEdit]byte)(unsafe.Pointer(x)))[:]
+}
+
 // struct tc_police {
 // 	__u32			index;
 // 	int			action;
@@ -708,3 +865,10 @@ const (
 	TCA_FQ_CODEL_DROP_BATCH_SIZE
 	TCA_FQ_CODEL_MEMORY_LIMIT
 )
+
+const (
+	TCA_HFSC_UNSPEC = iota
+	TCA_HFSC_RSC
+	TCA_HFSC_FSC
+	TCA_HFSC_USC
+)

+ 36 - 26
vendor/github.com/vishvananda/netlink/nl/xfrm_linux.go

@@ -50,34 +50,44 @@ const (
 // Attribute types
 const (
 	/* Netlink message attributes.  */
-	XFRMA_UNSPEC         = 0x00
-	XFRMA_ALG_AUTH       = 0x01 /* struct xfrm_algo */
-	XFRMA_ALG_CRYPT      = 0x02 /* struct xfrm_algo */
-	XFRMA_ALG_COMP       = 0x03 /* struct xfrm_algo */
-	XFRMA_ENCAP          = 0x04 /* struct xfrm_algo + struct xfrm_encap_tmpl */
-	XFRMA_TMPL           = 0x05 /* 1 or more struct xfrm_user_tmpl */
-	XFRMA_SA             = 0x06 /* struct xfrm_usersa_info  */
-	XFRMA_POLICY         = 0x07 /* struct xfrm_userpolicy_info */
-	XFRMA_SEC_CTX        = 0x08 /* struct xfrm_sec_ctx */
-	XFRMA_LTIME_VAL      = 0x09
-	XFRMA_REPLAY_VAL     = 0x0a
-	XFRMA_REPLAY_THRESH  = 0x0b
-	XFRMA_ETIMER_THRESH  = 0x0c
-	XFRMA_SRCADDR        = 0x0d /* xfrm_address_t */
-	XFRMA_COADDR         = 0x0e /* xfrm_address_t */
-	XFRMA_LASTUSED       = 0x0f /* unsigned long  */
-	XFRMA_POLICY_TYPE    = 0x10 /* struct xfrm_userpolicy_type */
-	XFRMA_MIGRATE        = 0x11
-	XFRMA_ALG_AEAD       = 0x12 /* struct xfrm_algo_aead */
-	XFRMA_KMADDRESS      = 0x13 /* struct xfrm_user_kmaddress */
-	XFRMA_ALG_AUTH_TRUNC = 0x14 /* struct xfrm_algo_auth */
-	XFRMA_MARK           = 0x15 /* struct xfrm_mark */
-	XFRMA_TFCPAD         = 0x16 /* __u32 */
-	XFRMA_REPLAY_ESN_VAL = 0x17 /* struct xfrm_replay_esn */
-	XFRMA_SA_EXTRA_FLAGS = 0x18 /* __u32 */
-	XFRMA_MAX            = 0x18
+	XFRMA_UNSPEC    = iota
+	XFRMA_ALG_AUTH  /* struct xfrm_algo */
+	XFRMA_ALG_CRYPT /* struct xfrm_algo */
+	XFRMA_ALG_COMP  /* struct xfrm_algo */
+	XFRMA_ENCAP     /* struct xfrm_algo + struct xfrm_encap_tmpl */
+	XFRMA_TMPL      /* 1 or more struct xfrm_user_tmpl */
+	XFRMA_SA        /* struct xfrm_usersa_info  */
+	XFRMA_POLICY    /* struct xfrm_userpolicy_info */
+	XFRMA_SEC_CTX   /* struct xfrm_sec_ctx */
+	XFRMA_LTIME_VAL
+	XFRMA_REPLAY_VAL
+	XFRMA_REPLAY_THRESH
+	XFRMA_ETIMER_THRESH
+	XFRMA_SRCADDR     /* xfrm_address_t */
+	XFRMA_COADDR      /* xfrm_address_t */
+	XFRMA_LASTUSED    /* unsigned long  */
+	XFRMA_POLICY_TYPE /* struct xfrm_userpolicy_type */
+	XFRMA_MIGRATE
+	XFRMA_ALG_AEAD       /* struct xfrm_algo_aead */
+	XFRMA_KMADDRESS      /* struct xfrm_user_kmaddress */
+	XFRMA_ALG_AUTH_TRUNC /* struct xfrm_algo_auth */
+	XFRMA_MARK           /* struct xfrm_mark */
+	XFRMA_TFCPAD         /* __u32 */
+	XFRMA_REPLAY_ESN_VAL /* struct xfrm_replay_esn */
+	XFRMA_SA_EXTRA_FLAGS /* __u32 */
+	XFRMA_PROTO          /* __u8 */
+	XFRMA_ADDRESS_FILTER /* struct xfrm_address_filter */
+	XFRMA_PAD
+	XFRMA_OFFLOAD_DEV   /* struct xfrm_state_offload */
+	XFRMA_SET_MARK      /* __u32 */
+	XFRMA_SET_MARK_MASK /* __u32 */
+	XFRMA_IF_ID         /* __u32 */
+
+	XFRMA_MAX = iota - 1
 )
 
+const XFRMA_OUTPUT_MARK = XFRMA_SET_MARK
+
 const (
 	SizeofXfrmAddress     = 0x10
 	SizeofXfrmSelector    = 0x38

+ 4 - 0
vendor/github.com/vishvananda/netlink/protinfo.go

@@ -18,6 +18,10 @@ type Protinfo struct {
 
 // String returns a list of enabled flags
 func (prot *Protinfo) String() string {
+	if prot == nil {
+		return "<nil>"
+	}
+
 	var boolStrings []string
 	if prot.Hairpin {
 		boolStrings = append(boolStrings, "Hairpin")

+ 3 - 4
vendor/github.com/vishvananda/netlink/protinfo_linux.go

@@ -41,7 +41,7 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
 			if err != nil {
 				return pi, err
 			}
-			pi = *parseProtinfo(infos)
+			pi = parseProtinfo(infos)
 
 			return pi, nil
 		}
@@ -49,8 +49,7 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
 	return pi, fmt.Errorf("Device with index %d not found", base.Index)
 }
 
-func parseProtinfo(infos []syscall.NetlinkRouteAttr) *Protinfo {
-	var pi Protinfo
+func parseProtinfo(infos []syscall.NetlinkRouteAttr) (pi Protinfo) {
 	for _, info := range infos {
 		switch info.Attr.Type {
 		case nl.IFLA_BRPORT_MODE:
@@ -71,5 +70,5 @@ func parseProtinfo(infos []syscall.NetlinkRouteAttr) *Protinfo {
 			pi.ProxyArpWiFi = byteToBool(info.Value[0])
 		}
 	}
-	return &pi
+	return
 }

+ 48 - 0
vendor/github.com/vishvananda/netlink/qdisc.go

@@ -176,6 +176,13 @@ type Netem struct {
 	CorruptCorr   uint32
 }
 
+func (netem *Netem) String() string {
+	return fmt.Sprintf(
+		"{Latency: %v, Limit: %v, Loss: %v, Gap: %v, Duplicate: %v, Jitter: %v}",
+		netem.Latency, netem.Limit, netem.Loss, netem.Gap, netem.Duplicate, netem.Jitter,
+	)
+}
+
 func (qdisc *Netem) Attrs() *QdiscAttrs {
 	return &qdisc.QdiscAttrs
 }
@@ -231,6 +238,33 @@ func (qdisc *GenericQdisc) Type() string {
 	return qdisc.QdiscType
 }
 
+type Hfsc struct {
+	QdiscAttrs
+	Defcls uint16
+}
+
+func NewHfsc(attrs QdiscAttrs) *Hfsc {
+	return &Hfsc{
+		QdiscAttrs: attrs,
+		Defcls:     1,
+	}
+}
+
+func (hfsc *Hfsc) Attrs() *QdiscAttrs {
+	return &hfsc.QdiscAttrs
+}
+
+func (hfsc *Hfsc) Type() string {
+	return "hfsc"
+}
+
+func (hfsc *Hfsc) String() string {
+	return fmt.Sprintf(
+		"{%v -- default: %d}",
+		hfsc.Attrs(), hfsc.Defcls,
+	)
+}
+
 // Fq is a classless packet scheduler meant to be mostly used for locally generated traffic.
 type Fq struct {
 	QdiscAttrs
@@ -249,6 +283,13 @@ type Fq struct {
 	LowRateThreshold uint32
 }
 
+func (fq *Fq) String() string {
+	return fmt.Sprintf(
+		"{PacketLimit: %v, FlowPacketLimit: %v, Quantum: %v, InitialQuantum: %v, Pacing: %v, FlowDefaultRate: %v, FlowMaxRate: %v, Buckets: %v, FlowRefillDelay: %v,  LowRateThreshold: %v}",
+		fq.PacketLimit, fq.FlowPacketLimit, fq.Quantum, fq.InitialQuantum, fq.Pacing, fq.FlowDefaultRate, fq.FlowMaxRate, fq.Buckets, fq.FlowRefillDelay, fq.LowRateThreshold,
+	)
+}
+
 func NewFq(attrs QdiscAttrs) *Fq {
 	return &Fq{
 		QdiscAttrs: attrs,
@@ -276,6 +317,13 @@ type FqCodel struct {
 	// There are some more attributes here, but support for them seems not ubiquitous
 }
 
+func (fqcodel *FqCodel) String() string {
+	return fmt.Sprintf(
+		"{%v -- Target: %v, Limit: %v, Interval: %v, ECM: %v, Flows: %v, Quantum: %v}",
+		fqcodel.Attrs(), fqcodel.Target, fqcodel.Limit, fqcodel.Interval, fqcodel.ECN, fqcodel.Flows, fqcodel.Quantum,
+	)
+}
+
 func NewFqCodel(attrs QdiscAttrs) *FqCodel {
 	return &FqCodel{
 		QdiscAttrs: attrs,

+ 45 - 24
vendor/github.com/vishvananda/netlink/qdisc_linux.go

@@ -175,15 +175,15 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
 		opt.Peakrate.Rate = uint32(qdisc.Peakrate)
 		opt.Limit = qdisc.Limit
 		opt.Buffer = qdisc.Buffer
-		nl.NewRtAttrChild(options, nl.TCA_TBF_PARMS, opt.Serialize())
+		options.AddRtAttr(nl.TCA_TBF_PARMS, opt.Serialize())
 		if qdisc.Rate >= uint64(1<<32) {
-			nl.NewRtAttrChild(options, nl.TCA_TBF_RATE64, nl.Uint64Attr(qdisc.Rate))
+			options.AddRtAttr(nl.TCA_TBF_RATE64, nl.Uint64Attr(qdisc.Rate))
 		}
 		if qdisc.Peakrate >= uint64(1<<32) {
-			nl.NewRtAttrChild(options, nl.TCA_TBF_PRATE64, nl.Uint64Attr(qdisc.Peakrate))
+			options.AddRtAttr(nl.TCA_TBF_PRATE64, nl.Uint64Attr(qdisc.Peakrate))
 		}
 		if qdisc.Peakrate > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_TBF_PBURST, nl.Uint32Attr(qdisc.Minburst))
+			options.AddRtAttr(nl.TCA_TBF_PBURST, nl.Uint32Attr(qdisc.Minburst))
 		}
 	case *Htb:
 		opt := nl.TcHtbGlob{}
@@ -193,8 +193,12 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
 		// TODO: Handle Debug properly. For now default to 0
 		opt.Debug = qdisc.Debug
 		opt.DirectPkts = qdisc.DirectPkts
-		nl.NewRtAttrChild(options, nl.TCA_HTB_INIT, opt.Serialize())
-		// nl.NewRtAttrChild(options, nl.TCA_HTB_DIRECT_QLEN, opt.Serialize())
+		options.AddRtAttr(nl.TCA_HTB_INIT, opt.Serialize())
+		// options.AddRtAttr(nl.TCA_HTB_DIRECT_QLEN, opt.Serialize())
+	case *Hfsc:
+		opt := nl.TcHfscOpt{}
+		opt.Defcls = qdisc.Defcls
+		options = nl.NewRtAttr(nl.TCA_OPTIONS, opt.Serialize())
 	case *Netem:
 		opt := nl.TcNetemQopt{}
 		opt.Latency = qdisc.Latency
@@ -211,21 +215,21 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
 		corr.DupCorr = qdisc.DuplicateCorr
 
 		if corr.DelayCorr > 0 || corr.LossCorr > 0 || corr.DupCorr > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_NETEM_CORR, corr.Serialize())
+			options.AddRtAttr(nl.TCA_NETEM_CORR, corr.Serialize())
 		}
 		// Corruption
 		corruption := nl.TcNetemCorrupt{}
 		corruption.Probability = qdisc.CorruptProb
 		corruption.Correlation = qdisc.CorruptCorr
 		if corruption.Probability > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_NETEM_CORRUPT, corruption.Serialize())
+			options.AddRtAttr(nl.TCA_NETEM_CORRUPT, corruption.Serialize())
 		}
 		// Reorder
 		reorder := nl.TcNetemReorder{}
 		reorder.Probability = qdisc.ReorderProb
 		reorder.Correlation = qdisc.ReorderCorr
 		if reorder.Probability > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_NETEM_REORDER, reorder.Serialize())
+			options.AddRtAttr(nl.TCA_NETEM_REORDER, reorder.Serialize())
 		}
 	case *Ingress:
 		// ingress filters must use the proper handle
@@ -233,50 +237,54 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
 			return fmt.Errorf("Ingress filters must set Parent to HANDLE_INGRESS")
 		}
 	case *FqCodel:
-		nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_ECN, nl.Uint32Attr((uint32(qdisc.ECN))))
+		options.AddRtAttr(nl.TCA_FQ_CODEL_ECN, nl.Uint32Attr((uint32(qdisc.ECN))))
 		if qdisc.Limit > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_LIMIT, nl.Uint32Attr((uint32(qdisc.Limit))))
+			options.AddRtAttr(nl.TCA_FQ_CODEL_LIMIT, nl.Uint32Attr((uint32(qdisc.Limit))))
 		}
 		if qdisc.Interval > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_INTERVAL, nl.Uint32Attr((uint32(qdisc.Interval))))
+			options.AddRtAttr(nl.TCA_FQ_CODEL_INTERVAL, nl.Uint32Attr((uint32(qdisc.Interval))))
 		}
 		if qdisc.Flows > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_FLOWS, nl.Uint32Attr((uint32(qdisc.Flows))))
+			options.AddRtAttr(nl.TCA_FQ_CODEL_FLOWS, nl.Uint32Attr((uint32(qdisc.Flows))))
 		}
 		if qdisc.Quantum > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
+			options.AddRtAttr(nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
 		}
 
 	case *Fq:
-		nl.NewRtAttrChild(options, nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing))))
+		options.AddRtAttr(nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing))))
 
 		if qdisc.Buckets > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_FQ_BUCKETS_LOG, nl.Uint32Attr((uint32(qdisc.Buckets))))
+			options.AddRtAttr(nl.TCA_FQ_BUCKETS_LOG, nl.Uint32Attr((uint32(qdisc.Buckets))))
 		}
 		if qdisc.LowRateThreshold > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_FQ_LOW_RATE_THRESHOLD, nl.Uint32Attr((uint32(qdisc.LowRateThreshold))))
+			options.AddRtAttr(nl.TCA_FQ_LOW_RATE_THRESHOLD, nl.Uint32Attr((uint32(qdisc.LowRateThreshold))))
 		}
 		if qdisc.Quantum > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_FQ_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
+			options.AddRtAttr(nl.TCA_FQ_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
 		}
 		if qdisc.InitialQuantum > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_FQ_INITIAL_QUANTUM, nl.Uint32Attr((uint32(qdisc.InitialQuantum))))
+			options.AddRtAttr(nl.TCA_FQ_INITIAL_QUANTUM, nl.Uint32Attr((uint32(qdisc.InitialQuantum))))
 		}
 		if qdisc.FlowRefillDelay > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_REFILL_DELAY, nl.Uint32Attr((uint32(qdisc.FlowRefillDelay))))
+			options.AddRtAttr(nl.TCA_FQ_FLOW_REFILL_DELAY, nl.Uint32Attr((uint32(qdisc.FlowRefillDelay))))
 		}
 		if qdisc.FlowPacketLimit > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_PLIMIT, nl.Uint32Attr((uint32(qdisc.FlowPacketLimit))))
+			options.AddRtAttr(nl.TCA_FQ_FLOW_PLIMIT, nl.Uint32Attr((uint32(qdisc.FlowPacketLimit))))
 		}
 		if qdisc.FlowMaxRate > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_MAX_RATE, nl.Uint32Attr((uint32(qdisc.FlowMaxRate))))
+			options.AddRtAttr(nl.TCA_FQ_FLOW_MAX_RATE, nl.Uint32Attr((uint32(qdisc.FlowMaxRate))))
 		}
 		if qdisc.FlowDefaultRate > 0 {
-			nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_DEFAULT_RATE, nl.Uint32Attr((uint32(qdisc.FlowDefaultRate))))
+			options.AddRtAttr(nl.TCA_FQ_FLOW_DEFAULT_RATE, nl.Uint32Attr((uint32(qdisc.FlowDefaultRate))))
 		}
+	default:
+		options = nil
 	}
 
-	req.AddData(options)
+	if options != nil {
+		req.AddData(options)
+	}
 	return nil
 }
 
@@ -348,6 +356,8 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
 					qdisc = &Htb{}
 				case "fq":
 					qdisc = &Fq{}
+				case "hfsc":
+					qdisc = &Hfsc{}
 				case "fq_codel":
 					qdisc = &FqCodel{}
 				case "netem":
@@ -375,6 +385,10 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
 					if err := parseTbfData(qdisc, data); err != nil {
 						return nil, err
 					}
+				case "hfsc":
+					if err := parseHfscData(qdisc, attr.Value); err != nil {
+						return nil, err
+					}
 				case "htb":
 					data, err := nl.ParseRouteAttr(attr.Value)
 					if err != nil {
@@ -474,6 +488,13 @@ func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
 	return nil
 }
 
+func parseHfscData(qdisc Qdisc, data []byte) error {
+	Hfsc := qdisc.(*Hfsc)
+	native = nl.NativeEndian()
+	Hfsc.Defcls = native.Uint16(data)
+	return nil
+}
+
 func parseFqData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
 	native = nl.NativeEndian()
 	fq := qdisc.(*Fq)

+ 264 - 0
vendor/github.com/vishvananda/netlink/rdma_link_linux.go

@@ -0,0 +1,264 @@
+package netlink
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"net"
+
+	"github.com/vishvananda/netlink/nl"
+	"golang.org/x/sys/unix"
+)
+
+// LinkAttrs represents data shared by most link types
+type RdmaLinkAttrs struct {
+	Index           uint32
+	Name            string
+	FirmwareVersion string
+	NodeGuid        string
+	SysImageGuid    string
+}
+
+// Link represents a rdma device from netlink.
+type RdmaLink struct {
+	Attrs RdmaLinkAttrs
+}
+
+func getProtoField(clientType int, op int) int {
+	return ((clientType << nl.RDMA_NL_GET_CLIENT_SHIFT) | op)
+}
+
+func uint64ToGuidString(guid uint64) string {
+	//Convert to byte array
+	sysGuidBytes := new(bytes.Buffer)
+	binary.Write(sysGuidBytes, binary.LittleEndian, guid)
+
+	//Convert to HardwareAddr
+	sysGuidNet := net.HardwareAddr(sysGuidBytes.Bytes())
+
+	//Get the String
+	return sysGuidNet.String()
+}
+
+func executeOneGetRdmaLink(data []byte) (*RdmaLink, error) {
+
+	link := RdmaLink{}
+
+	reader := bytes.NewReader(data)
+	for reader.Len() >= 4 {
+		_, attrType, len, value := parseNfAttrTLV(reader)
+
+		switch attrType {
+		case nl.RDMA_NLDEV_ATTR_DEV_INDEX:
+			var Index uint32
+			r := bytes.NewReader(value)
+			binary.Read(r, nl.NativeEndian(), &Index)
+			link.Attrs.Index = Index
+		case nl.RDMA_NLDEV_ATTR_DEV_NAME:
+			link.Attrs.Name = string(value[0 : len-1])
+		case nl.RDMA_NLDEV_ATTR_FW_VERSION:
+			link.Attrs.FirmwareVersion = string(value[0 : len-1])
+		case nl.RDMA_NLDEV_ATTR_NODE_GUID:
+			var guid uint64
+			r := bytes.NewReader(value)
+			binary.Read(r, nl.NativeEndian(), &guid)
+			link.Attrs.NodeGuid = uint64ToGuidString(guid)
+		case nl.RDMA_NLDEV_ATTR_SYS_IMAGE_GUID:
+			var sysGuid uint64
+			r := bytes.NewReader(value)
+			binary.Read(r, nl.NativeEndian(), &sysGuid)
+			link.Attrs.SysImageGuid = uint64ToGuidString(sysGuid)
+		}
+		if (len % 4) != 0 {
+			// Skip pad bytes
+			reader.Seek(int64(4-(len%4)), seekCurrent)
+		}
+	}
+	return &link, nil
+}
+
+func execRdmaGetLink(req *nl.NetlinkRequest, name string) (*RdmaLink, error) {
+
+	msgs, err := req.Execute(unix.NETLINK_RDMA, 0)
+	if err != nil {
+		return nil, err
+	}
+	for _, m := range msgs {
+		link, err := executeOneGetRdmaLink(m)
+		if err != nil {
+			return nil, err
+		}
+		if link.Attrs.Name == name {
+			return link, nil
+		}
+	}
+	return nil, fmt.Errorf("Rdma device %v not found", name)
+}
+
+func execRdmaSetLink(req *nl.NetlinkRequest) error {
+
+	_, err := req.Execute(unix.NETLINK_RDMA, 0)
+	return err
+}
+
+// RdmaLinkByName finds a link by name and returns a pointer to the object if
+// found and nil error, otherwise returns error code.
+func RdmaLinkByName(name string) (*RdmaLink, error) {
+	return pkgHandle.RdmaLinkByName(name)
+}
+
+// RdmaLinkByName finds a link by name and returns a pointer to the object if
+// found and nil error, otherwise returns error code.
+func (h *Handle) RdmaLinkByName(name string) (*RdmaLink, error) {
+
+	proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_GET)
+	req := h.newNetlinkRequest(proto, unix.NLM_F_ACK|unix.NLM_F_DUMP)
+
+	return execRdmaGetLink(req, name)
+}
+
+// RdmaLinkSetName sets the name of the rdma link device. Return nil on success
+// or error otherwise.
+// Equivalent to: `rdma dev set $old_devname name $name`
+func RdmaLinkSetName(link *RdmaLink, name string) error {
+	return pkgHandle.RdmaLinkSetName(link, name)
+}
+
+// RdmaLinkSetName sets the name of the rdma link device. Return nil on success
+// or error otherwise.
+// Equivalent to: `rdma dev set $old_devname name $name`
+func (h *Handle) RdmaLinkSetName(link *RdmaLink, name string) error {
+	proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SET)
+	req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
+
+	b := make([]byte, 4)
+	native.PutUint32(b, uint32(link.Attrs.Index))
+	data := nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX, b)
+	req.AddData(data)
+
+	b = make([]byte, len(name)+1)
+	copy(b, name)
+	data = nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_NAME, b)
+	req.AddData(data)
+
+	return execRdmaSetLink(req)
+}
+
+func netnsModeToString(mode uint8) string {
+	switch mode {
+	case 0:
+		return "exclusive"
+	case 1:
+		return "shared"
+	default:
+		return "unknown"
+	}
+}
+
+func executeOneGetRdmaNetnsMode(data []byte) (string, error) {
+	reader := bytes.NewReader(data)
+	for reader.Len() >= 4 {
+		_, attrType, len, value := parseNfAttrTLV(reader)
+
+		switch attrType {
+		case nl.RDMA_NLDEV_SYS_ATTR_NETNS_MODE:
+			var mode uint8
+			r := bytes.NewReader(value)
+			binary.Read(r, nl.NativeEndian(), &mode)
+			return netnsModeToString(mode), nil
+		}
+		if (len % 4) != 0 {
+			// Skip pad bytes
+			reader.Seek(int64(4-(len%4)), seekCurrent)
+		}
+	}
+	return "", fmt.Errorf("Invalid netns mode")
+}
+
+// RdmaSystemGetNetnsMode gets the net namespace mode for RDMA subsystem
+// Returns mode string and error status as nil on success or returns error
+// otherwise.
+// Equivalent to: `rdma system show netns'
+func RdmaSystemGetNetnsMode() (string, error) {
+	return pkgHandle.RdmaSystemGetNetnsMode()
+}
+
+// RdmaSystemGetNetnsMode gets the net namespace mode for RDMA subsystem
+// Returns mode string and error status as nil on success or returns error
+// otherwise.
+// Equivalent to: `rdma system show netns'
+func (h *Handle) RdmaSystemGetNetnsMode() (string, error) {
+
+	proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SYS_GET)
+	req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
+
+	msgs, err := req.Execute(unix.NETLINK_RDMA, 0)
+	if err != nil {
+		return "", err
+	}
+	if len(msgs) == 0 {
+		return "", fmt.Errorf("No valid response from kernel")
+	}
+	return executeOneGetRdmaNetnsMode(msgs[0])
+}
+
+func netnsModeStringToUint8(mode string) (uint8, error) {
+	switch mode {
+	case "exclusive":
+		return 0, nil
+	case "shared":
+		return 1, nil
+	default:
+		return 0, fmt.Errorf("Invalid mode; %q", mode)
+	}
+}
+
+// RdmaSystemSetNetnsMode sets the net namespace mode for RDMA subsystem
+// Returns nil on success or appropriate error code.
+// Equivalent to: `rdma system set netns { shared | exclusive }'
+func RdmaSystemSetNetnsMode(NewMode string) error {
+	return pkgHandle.RdmaSystemSetNetnsMode(NewMode)
+}
+
+// RdmaSystemSetNetnsMode sets the net namespace mode for RDMA subsystem
+// Returns nil on success or appropriate error code.
+// Equivalent to: `rdma system set netns { shared | exclusive }'
+func (h *Handle) RdmaSystemSetNetnsMode(NewMode string) error {
+	value, err := netnsModeStringToUint8(NewMode)
+	if err != nil {
+		return err
+	}
+
+	proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SYS_SET)
+	req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
+
+	data := nl.NewRtAttr(nl.RDMA_NLDEV_SYS_ATTR_NETNS_MODE, []byte{value})
+	req.AddData(data)
+
+	_, err = req.Execute(unix.NETLINK_RDMA, 0)
+	return err
+}
+
+// RdmaLinkSetNsFd puts the RDMA device into a new network namespace. The
+// fd must be an open file descriptor to a network namespace.
+// Similar to: `rdma dev set $dev netns $ns`
+func RdmaLinkSetNsFd(link *RdmaLink, fd uint32) error {
+	return pkgHandle.RdmaLinkSetNsFd(link, fd)
+}
+
+// RdmaLinkSetNsFd puts the RDMA device into a new network namespace. The
+// fd must be an open file descriptor to a network namespace.
+// Similar to: `rdma dev set $dev netns $ns`
+func (h *Handle) RdmaLinkSetNsFd(link *RdmaLink, fd uint32) error {
+	proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SET)
+	req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
+
+	data := nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX,
+		nl.Uint32Attr(link.Attrs.Index))
+	req.AddData(data)
+
+	data = nl.NewRtAttr(nl.RDMA_NLDEV_NET_NS_FD, nl.Uint32Attr(fd))
+	req.AddData(data)
+
+	return execRdmaSetLink(req)
+}

+ 2 - 0
vendor/github.com/vishvananda/netlink/route.go

@@ -47,6 +47,7 @@ type Route struct {
 	Encap      Encap
 	MTU        int
 	AdvMSS     int
+	Hoplimit   int
 }
 
 func (r Route) String() string {
@@ -89,6 +90,7 @@ func (r Route) Equal(x Route) bool {
 		r.Table == x.Table &&
 		r.Type == x.Type &&
 		r.Tos == x.Tos &&
+		r.Hoplimit == x.Hoplimit &&
 		r.Flags == x.Flags &&
 		(r.MPLSDst == x.MPLSDst || (r.MPLSDst != nil && x.MPLSDst != nil && *r.MPLSDst == *x.MPLSDst)) &&
 		(r.NewDst == x.NewDst || (r.NewDst != nil && r.NewDst.Equal(x.NewDst))) &&

+ 216 - 13
vendor/github.com/vishvananda/netlink/route_linux.go

@@ -32,6 +32,7 @@ const (
 	RT_FILTER_SRC
 	RT_FILTER_GW
 	RT_FILTER_TABLE
+	RT_FILTER_HOPLIMIT
 )
 
 const (
@@ -207,6 +208,7 @@ func (e *SEG6Encap) Decode(buf []byte) error {
 	}
 	buf = buf[:l] // make sure buf size upper limit is Length
 	typ := native.Uint16(buf[2:])
+	// LWTUNNEL_ENCAP_SEG6 has only one attr type SEG6_IPTUNNEL_SRH
 	if typ != nl.SEG6_IPTUNNEL_SRH {
 		return fmt.Errorf("unknown SEG6 Type: %d", typ)
 	}
@@ -259,6 +261,188 @@ func (e *SEG6Encap) Equal(x Encap) bool {
 	return true
 }
 
+// SEG6LocalEncap definitions
+type SEG6LocalEncap struct {
+	Flags    [nl.SEG6_LOCAL_MAX]bool
+	Action   int
+	Segments []net.IP // from SRH in seg6_local_lwt
+	Table    int      // table id for End.T and End.DT6
+	InAddr   net.IP
+	In6Addr  net.IP
+	Iif      int
+	Oif      int
+}
+
+func (e *SEG6LocalEncap) Type() int {
+	return nl.LWTUNNEL_ENCAP_SEG6_LOCAL
+}
+func (e *SEG6LocalEncap) Decode(buf []byte) error {
+	attrs, err := nl.ParseRouteAttr(buf)
+	if err != nil {
+		return err
+	}
+	native := nl.NativeEndian()
+	for _, attr := range attrs {
+		switch attr.Attr.Type {
+		case nl.SEG6_LOCAL_ACTION:
+			e.Action = int(native.Uint32(attr.Value[0:4]))
+			e.Flags[nl.SEG6_LOCAL_ACTION] = true
+		case nl.SEG6_LOCAL_SRH:
+			e.Segments, err = nl.DecodeSEG6Srh(attr.Value[:])
+			e.Flags[nl.SEG6_LOCAL_SRH] = true
+		case nl.SEG6_LOCAL_TABLE:
+			e.Table = int(native.Uint32(attr.Value[0:4]))
+			e.Flags[nl.SEG6_LOCAL_TABLE] = true
+		case nl.SEG6_LOCAL_NH4:
+			e.InAddr = net.IP(attr.Value[0:4])
+			e.Flags[nl.SEG6_LOCAL_NH4] = true
+		case nl.SEG6_LOCAL_NH6:
+			e.In6Addr = net.IP(attr.Value[0:16])
+			e.Flags[nl.SEG6_LOCAL_NH6] = true
+		case nl.SEG6_LOCAL_IIF:
+			e.Iif = int(native.Uint32(attr.Value[0:4]))
+			e.Flags[nl.SEG6_LOCAL_IIF] = true
+		case nl.SEG6_LOCAL_OIF:
+			e.Oif = int(native.Uint32(attr.Value[0:4]))
+			e.Flags[nl.SEG6_LOCAL_OIF] = true
+		}
+	}
+	return err
+}
+func (e *SEG6LocalEncap) Encode() ([]byte, error) {
+	var err error
+	native := nl.NativeEndian()
+	res := make([]byte, 8)
+	native.PutUint16(res, 8) // length
+	native.PutUint16(res[2:], nl.SEG6_LOCAL_ACTION)
+	native.PutUint32(res[4:], uint32(e.Action))
+	if e.Flags[nl.SEG6_LOCAL_SRH] {
+		srh, err := nl.EncodeSEG6Srh(e.Segments)
+		if err != nil {
+			return nil, err
+		}
+		attr := make([]byte, 4)
+		native.PutUint16(attr, uint16(len(srh)+4))
+		native.PutUint16(attr[2:], nl.SEG6_LOCAL_SRH)
+		attr = append(attr, srh...)
+		res = append(res, attr...)
+	}
+	if e.Flags[nl.SEG6_LOCAL_TABLE] {
+		attr := make([]byte, 8)
+		native.PutUint16(attr, 8)
+		native.PutUint16(attr[2:], nl.SEG6_LOCAL_TABLE)
+		native.PutUint32(attr[4:], uint32(e.Table))
+		res = append(res, attr...)
+	}
+	if e.Flags[nl.SEG6_LOCAL_NH4] {
+		attr := make([]byte, 4)
+		native.PutUint16(attr, 8)
+		native.PutUint16(attr[2:], nl.SEG6_LOCAL_NH4)
+		ipv4 := e.InAddr.To4()
+		if ipv4 == nil {
+			err = fmt.Errorf("SEG6_LOCAL_NH4 has invalid IPv4 address")
+			return nil, err
+		}
+		attr = append(attr, ipv4...)
+		res = append(res, attr...)
+	}
+	if e.Flags[nl.SEG6_LOCAL_NH6] {
+		attr := make([]byte, 4)
+		native.PutUint16(attr, 20)
+		native.PutUint16(attr[2:], nl.SEG6_LOCAL_NH6)
+		attr = append(attr, e.In6Addr...)
+		res = append(res, attr...)
+	}
+	if e.Flags[nl.SEG6_LOCAL_IIF] {
+		attr := make([]byte, 8)
+		native.PutUint16(attr, 8)
+		native.PutUint16(attr[2:], nl.SEG6_LOCAL_IIF)
+		native.PutUint32(attr[4:], uint32(e.Iif))
+		res = append(res, attr...)
+	}
+	if e.Flags[nl.SEG6_LOCAL_OIF] {
+		attr := make([]byte, 8)
+		native.PutUint16(attr, 8)
+		native.PutUint16(attr[2:], nl.SEG6_LOCAL_OIF)
+		native.PutUint32(attr[4:], uint32(e.Oif))
+		res = append(res, attr...)
+	}
+	return res, err
+}
+func (e *SEG6LocalEncap) String() string {
+	strs := make([]string, 0, nl.SEG6_LOCAL_MAX)
+	strs = append(strs, fmt.Sprintf("action %s", nl.SEG6LocalActionString(e.Action)))
+
+	if e.Flags[nl.SEG6_LOCAL_TABLE] {
+		strs = append(strs, fmt.Sprintf("table %d", e.Table))
+	}
+	if e.Flags[nl.SEG6_LOCAL_NH4] {
+		strs = append(strs, fmt.Sprintf("nh4 %s", e.InAddr))
+	}
+	if e.Flags[nl.SEG6_LOCAL_NH6] {
+		strs = append(strs, fmt.Sprintf("nh6 %s", e.In6Addr))
+	}
+	if e.Flags[nl.SEG6_LOCAL_IIF] {
+		link, err := LinkByIndex(e.Iif)
+		if err != nil {
+			strs = append(strs, fmt.Sprintf("iif %d", e.Iif))
+		} else {
+			strs = append(strs, fmt.Sprintf("iif %s", link.Attrs().Name))
+		}
+	}
+	if e.Flags[nl.SEG6_LOCAL_OIF] {
+		link, err := LinkByIndex(e.Oif)
+		if err != nil {
+			strs = append(strs, fmt.Sprintf("oif %d", e.Oif))
+		} else {
+			strs = append(strs, fmt.Sprintf("oif %s", link.Attrs().Name))
+		}
+	}
+	if e.Flags[nl.SEG6_LOCAL_SRH] {
+		segs := make([]string, 0, len(e.Segments))
+		//append segment backwards (from n to 0) since seg#0 is the last segment.
+		for i := len(e.Segments); i > 0; i-- {
+			segs = append(segs, fmt.Sprintf("%s", e.Segments[i-1]))
+		}
+		strs = append(strs, fmt.Sprintf("segs %d [ %s ]", len(e.Segments), strings.Join(segs, " ")))
+	}
+	return strings.Join(strs, " ")
+}
+func (e *SEG6LocalEncap) Equal(x Encap) bool {
+	o, ok := x.(*SEG6LocalEncap)
+	if !ok {
+		return false
+	}
+	if e == o {
+		return true
+	}
+	if e == nil || o == nil {
+		return false
+	}
+	// compare all arrays first
+	for i := range e.Flags {
+		if e.Flags[i] != o.Flags[i] {
+			return false
+		}
+	}
+	if len(e.Segments) != len(o.Segments) {
+		return false
+	}
+	for i := range e.Segments {
+		if !e.Segments[i].Equal(o.Segments[i]) {
+			return false
+		}
+	}
+	// compare values
+	if !e.InAddr.Equal(o.InAddr) || !e.In6Addr.Equal(o.In6Addr) {
+		return false
+	}
+	if e.Action != o.Action || e.Table != o.Table || e.Iif != o.Iif || e.Oif != o.Oif {
+		return false
+	}
+	return true
+}
+
 // RouteAdd will add a route to the system.
 // Equivalent to: `ip route add $route`
 func RouteAdd(route *Route) error {
@@ -335,18 +519,18 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
 		if err != nil {
 			return err
 		}
-		rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_NEWDST, buf))
+		rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_NEWDST, buf))
 	}
 
 	if route.Encap != nil {
 		buf := make([]byte, 2)
 		native.PutUint16(buf, uint16(route.Encap.Type()))
-		rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_ENCAP_TYPE, buf))
+		rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP_TYPE, buf))
 		buf, err := route.Encap.Encode()
 		if err != nil {
 			return err
 		}
-		rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_ENCAP, buf))
+		rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP, buf))
 	}
 
 	if route.Src != nil {
@@ -410,17 +594,17 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
 				if err != nil {
 					return err
 				}
-				children = append(children, nl.NewRtAttr(nl.RTA_NEWDST, buf))
+				children = append(children, nl.NewRtAttr(unix.RTA_NEWDST, buf))
 			}
 			if nh.Encap != nil {
 				buf := make([]byte, 2)
 				native.PutUint16(buf, uint16(nh.Encap.Type()))
-				rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_ENCAP_TYPE, buf))
+				children = append(children, nl.NewRtAttr(unix.RTA_ENCAP_TYPE, buf))
 				buf, err := nh.Encap.Encode()
 				if err != nil {
 					return err
 				}
-				children = append(children, nl.NewRtAttr(nl.RTA_ENCAP, buf))
+				children = append(children, nl.NewRtAttr(unix.RTA_ENCAP, buf))
 			}
 			rtnh.Children = children
 			buf = append(buf, rtnh.Serialize()...)
@@ -464,6 +648,10 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
 		b := nl.Uint32Attr(uint32(route.AdvMSS))
 		metrics = append(metrics, nl.NewRtAttr(unix.RTAX_ADVMSS, b))
 	}
+	if route.Hoplimit > 0 {
+		b := nl.Uint32Attr(uint32(route.Hoplimit))
+		metrics = append(metrics, nl.NewRtAttr(unix.RTAX_HOPLIMIT, b))
+	}
 
 	if metrics != nil {
 		attr := nl.NewRtAttr(unix.RTA_METRICS, nil)
@@ -574,6 +762,8 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
 						continue
 					}
 				}
+			case filterMask&RT_FILTER_HOPLIMIT != 0 && route.Hoplimit != filter.Hoplimit:
+				continue
 			}
 		}
 		res = append(res, route)
@@ -649,7 +839,7 @@ func deserializeRoute(m []byte) (Route, error) {
 					switch attr.Attr.Type {
 					case unix.RTA_GATEWAY:
 						info.Gw = net.IP(attr.Value)
-					case nl.RTA_NEWDST:
+					case unix.RTA_NEWDST:
 						var d Destination
 						switch msg.Family {
 						case nl.FAMILY_MPLS:
@@ -659,9 +849,9 @@ func deserializeRoute(m []byte) (Route, error) {
 							return nil, nil, err
 						}
 						info.NewDst = d
-					case nl.RTA_ENCAP_TYPE:
+					case unix.RTA_ENCAP_TYPE:
 						encapType = attr
-					case nl.RTA_ENCAP:
+					case unix.RTA_ENCAP:
 						encap = attr
 					}
 				}
@@ -690,7 +880,7 @@ func deserializeRoute(m []byte) (Route, error) {
 				route.MultiPath = append(route.MultiPath, info)
 				rest = buf
 			}
-		case nl.RTA_NEWDST:
+		case unix.RTA_NEWDST:
 			var d Destination
 			switch msg.Family {
 			case nl.FAMILY_MPLS:
@@ -700,9 +890,9 @@ func deserializeRoute(m []byte) (Route, error) {
 				return route, err
 			}
 			route.NewDst = d
-		case nl.RTA_ENCAP_TYPE:
+		case unix.RTA_ENCAP_TYPE:
 			encapType = attr
-		case nl.RTA_ENCAP:
+		case unix.RTA_ENCAP:
 			encap = attr
 		case unix.RTA_METRICS:
 			metrics, err := nl.ParseRouteAttr(attr.Value)
@@ -715,6 +905,8 @@ func deserializeRoute(m []byte) (Route, error) {
 					route.MTU = int(native.Uint32(metric.Value[0:4]))
 				case unix.RTAX_ADVMSS:
 					route.AdvMSS = int(native.Uint32(metric.Value[0:4]))
+				case unix.RTAX_HOPLIMIT:
+					route.Hoplimit = int(native.Uint32(metric.Value[0:4]))
 				}
 			}
 		}
@@ -734,6 +926,11 @@ func deserializeRoute(m []byte) (Route, error) {
 			if err := e.Decode(encap.Value); err != nil {
 				return route, err
 			}
+		case nl.LWTUNNEL_ENCAP_SEG6_LOCAL:
+			e = &SEG6LocalEncap{}
+			if err := e.Decode(encap.Value); err != nil {
+				return route, err
+			}
 		}
 		route.Encap = e
 	}
@@ -840,13 +1037,19 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
 	go func() {
 		defer close(ch)
 		for {
-			msgs, err := s.Receive()
+			msgs, from, err := s.Receive()
 			if err != nil {
 				if cberr != nil {
 					cberr(err)
 				}
 				return
 			}
+			if from.Pid != nl.PidKernel {
+				if cberr != nil {
+					cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel))
+				}
+				continue
+			}
 			for _, m := range msgs {
 				if m.Header.Type == unix.NLMSG_DONE {
 					continue

+ 1 - 1
vendor/github.com/vishvananda/netlink/rule_linux.go

@@ -144,7 +144,7 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
 		req.AddData(nl.NewRtAttr(nl.FRA_OIFNAME, []byte(rule.OifName)))
 	}
 	if rule.Goto >= 0 {
-		msg.Type = nl.FR_ACT_NOP
+		msg.Type = nl.FR_ACT_GOTO
 		b := make([]byte, 4)
 		native.PutUint32(b, uint32(rule.Goto))
 		req.AddData(nl.NewRtAttr(nl.FRA_GOTO, b))

+ 4 - 1
vendor/github.com/vishvananda/netlink/socket_linux.go

@@ -141,10 +141,13 @@ func SocketGet(local, remote net.Addr) (*Socket, error) {
 		},
 	})
 	s.Send(req)
-	msgs, err := s.Receive()
+	msgs, from, err := s.Receive()
 	if err != nil {
 		return nil, err
 	}
+	if from.Pid != nl.PidKernel {
+		return nil, fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)
+	}
 	if len(msgs) == 0 {
 		return nil, errors.New("no message nor error from netlink")
 	}

+ 5 - 1
vendor/github.com/vishvananda/netlink/xfrm_monitor_linux.go

@@ -54,11 +54,15 @@ func XfrmMonitor(ch chan<- XfrmMsg, done <-chan struct{}, errorChan chan<- error
 	go func() {
 		defer close(ch)
 		for {
-			msgs, err := s.Receive()
+			msgs, from, err := s.Receive()
 			if err != nil {
 				errorChan <- err
 				return
 			}
+			if from.Pid != nl.PidKernel {
+				errorChan <- fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)
+				return
+			}
 			for _, m := range msgs {
 				switch m.Header.Type {
 				case nl.XFRM_MSG_EXPIRE:

+ 24 - 2
vendor/github.com/vishvananda/netlink/xfrm_policy.go

@@ -35,6 +35,25 @@ func (d Dir) String() string {
 	return fmt.Sprintf("socket %d", d-XFRM_SOCKET_IN)
 }
 
+// PolicyAction is an enum representing an ipsec policy action.
+type PolicyAction uint8
+
+const (
+	XFRM_POLICY_ALLOW PolicyAction = 0
+	XFRM_POLICY_BLOCK PolicyAction = 1
+)
+
+func (a PolicyAction) String() string {
+	switch a {
+	case XFRM_POLICY_ALLOW:
+		return "allow"
+	case XFRM_POLICY_BLOCK:
+		return "block"
+	default:
+		return fmt.Sprintf("action %d", a)
+	}
+}
+
 // XfrmPolicyTmpl encapsulates a rule for the base addresses of an ipsec
 // policy. These rules are matched with XfrmState to determine encryption
 // and authentication algorithms.
@@ -64,11 +83,14 @@ type XfrmPolicy struct {
 	Dir      Dir
 	Priority int
 	Index    int
+	Action   PolicyAction
+	Ifindex  int
+	Ifid     int
 	Mark     *XfrmMark
 	Tmpls    []XfrmPolicyTmpl
 }
 
 func (p XfrmPolicy) String() string {
-	return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, DstPort: %d, SrcPort: %d, Dir: %s, Priority: %d, Index: %d, Mark: %s, Tmpls: %s}",
-		p.Dst, p.Src, p.Proto, p.DstPort, p.SrcPort, p.Dir, p.Priority, p.Index, p.Mark, p.Tmpls)
+	return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, DstPort: %d, SrcPort: %d, Dir: %s, Priority: %d, Index: %d, Action: %s, Ifindex: %d, Ifid: %d, Mark: %s, Tmpls: %s}",
+		p.Dst, p.Src, p.Proto, p.DstPort, p.SrcPort, p.Dir, p.Priority, p.Index, p.Action, p.Ifindex, p.Ifid, p.Mark, p.Tmpls)
 }

+ 13 - 6
vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go

@@ -27,6 +27,7 @@ func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) {
 	if sel.Sport != 0 {
 		sel.SportMask = ^uint16(0)
 	}
+	sel.Ifindex = int32(policy.Ifindex)
 }
 
 // XfrmPolicyAdd will add an xfrm policy to the system.
@@ -61,6 +62,7 @@ func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
 	msg.Priority = uint32(policy.Priority)
 	msg.Index = uint32(policy.Index)
 	msg.Dir = uint8(policy.Dir)
+	msg.Action = uint8(policy.Action)
 	msg.Lft.SoftByteLimit = nl.XFRM_INF
 	msg.Lft.HardByteLimit = nl.XFRM_INF
 	msg.Lft.SoftPacketLimit = nl.XFRM_INF
@@ -90,6 +92,9 @@ func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
 		req.AddData(out)
 	}
 
+	ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid)))
+	req.AddData(ifId)
+
 	_, err := req.Execute(unix.NETLINK_XFRM, 0)
 	return err
 }
@@ -183,6 +188,9 @@ func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPo
 		req.AddData(out)
 	}
 
+	ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid)))
+	req.AddData(ifId)
+
 	resType := nl.XFRM_MSG_NEWPOLICY
 	if nlProto == nl.XFRM_MSG_DELPOLICY {
 		resType = 0
@@ -197,12 +205,7 @@ func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPo
 		return nil, err
 	}
 
-	p, err := parseXfrmPolicy(msgs[0], FAMILY_ALL)
-	if err != nil {
-		return nil, err
-	}
-
-	return p, nil
+	return parseXfrmPolicy(msgs[0], FAMILY_ALL)
 }
 
 func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) {
@@ -220,9 +223,11 @@ func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) {
 	policy.Proto = Proto(msg.Sel.Proto)
 	policy.DstPort = int(nl.Swap16(msg.Sel.Dport))
 	policy.SrcPort = int(nl.Swap16(msg.Sel.Sport))
+	policy.Ifindex = int(msg.Sel.Ifindex)
 	policy.Priority = int(msg.Priority)
 	policy.Index = int(msg.Index)
 	policy.Dir = Dir(msg.Dir)
+	policy.Action = PolicyAction(msg.Action)
 
 	attrs, err := nl.ParseRouteAttr(m[msg.Len():])
 	if err != nil {
@@ -249,6 +254,8 @@ func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) {
 			policy.Mark = new(XfrmMark)
 			policy.Mark.Value = mark.Value
 			policy.Mark.Mask = mark.Mask
+		case nl.XFRMA_IF_ID:
+			policy.Ifid = int(native.Uint32(attr.Value))
 		}
 	}
 

+ 4 - 2
vendor/github.com/vishvananda/netlink/xfrm_state.go

@@ -94,6 +94,8 @@ type XfrmState struct {
 	Limits       XfrmStateLimits
 	Statistics   XfrmStateStats
 	Mark         *XfrmMark
+	OutputMark   int
+	Ifid         int
 	Auth         *XfrmStateAlgo
 	Crypt        *XfrmStateAlgo
 	Aead         *XfrmStateAlgo
@@ -102,8 +104,8 @@ type XfrmState struct {
 }
 
 func (sa XfrmState) String() string {
-	return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, Auth: %v, Crypt: %v, Aead: %v, Encap: %v, ESN: %t",
-		sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.Auth, sa.Crypt, sa.Aead, sa.Encap, sa.ESN)
+	return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, OutputMark: %d, Ifid: %d, Auth: %v, Crypt: %v, Aead: %v, Encap: %v, ESN: %t",
+		sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.OutputMark, sa.Ifid, sa.Auth, sa.Crypt, sa.Aead, sa.Encap, sa.ESN)
 }
 func (sa XfrmState) Print(stats bool) string {
 	if !stats {

+ 16 - 11
vendor/github.com/vishvananda/netlink/xfrm_state_linux.go

@@ -158,6 +158,13 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
 		out := nl.NewRtAttr(nl.XFRMA_REPLAY_ESN_VAL, writeReplayEsn(state.ReplayWindow))
 		req.AddData(out)
 	}
+	if state.OutputMark != 0 {
+		out := nl.NewRtAttr(nl.XFRMA_OUTPUT_MARK, nl.Uint32Attr(uint32(state.OutputMark)))
+		req.AddData(out)
+	}
+
+	ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid)))
+	req.AddData(ifId)
 
 	_, err := req.Execute(unix.NETLINK_XFRM, 0)
 	return err
@@ -184,12 +191,7 @@ func (h *Handle) xfrmStateAllocSpi(state *XfrmState) (*XfrmState, error) {
 		return nil, err
 	}
 
-	s, err := parseXfrmState(msgs[0], FAMILY_ALL)
-	if err != nil {
-		return nil, err
-	}
-
-	return s, err
+	return parseXfrmState(msgs[0], FAMILY_ALL)
 }
 
 // XfrmStateDel will delete an xfrm state from the system. Note that
@@ -275,6 +277,9 @@ func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState
 		req.AddData(out)
 	}
 
+	ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid)))
+	req.AddData(ifId)
+
 	resType := nl.XFRM_MSG_NEWSA
 	if nlProto == nl.XFRM_MSG_DELSA {
 		resType = 0
@@ -372,6 +377,10 @@ func parseXfrmState(m []byte, family int) (*XfrmState, error) {
 			state.Mark = new(XfrmMark)
 			state.Mark.Value = mark.Value
 			state.Mark.Mask = mark.Mask
+		case nl.XFRMA_OUTPUT_MARK:
+			state.OutputMark = int(native.Uint32(attr.Value))
+		case nl.XFRMA_IF_ID:
+			state.Ifid = int(native.Uint32(attr.Value))
 		}
 	}
 
@@ -394,11 +403,7 @@ func (h *Handle) XfrmStateFlush(proto Proto) error {
 	req.AddData(&nl.XfrmUsersaFlush{Proto: uint8(proto)})
 
 	_, err := req.Execute(unix.NETLINK_XFRM, 0)
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return err
 }
 
 func limitsToLft(lmts XfrmStateLimits, lft *nl.XfrmLifetimeCfg) {

+ 3 - 0
vendor/github.com/vishvananda/netns/go.mod

@@ -0,0 +1,3 @@
+module github.com/vishvananda/netns
+
+go 1.12

Vissa filer visades inte eftersom för många filer har ändrats