Merge pull request from thaJeztah/19.03_backport_bump_libnetwork

[19.03 backport] bump libnetwork to 92d1fbe1eb0883cf11d283cea8e658275146411d
This commit is contained in:
Andrew Hsu 2019-09-16 16:12:22 -07:00 committed by GitHub
commit c416072ced
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
310 changed files with 38217 additions and 5112 deletions
hack/dockerfile/install
vendor.conf
vendor
github.com
go.etcd.io/bbolt

View file

@ -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=fc5a7d91d54cc98f64fc28f9e288b46a0bee756c
LIBNETWORK_COMMIT=92d1fbe1eb0883cf11d283cea8e658275146411d
install_proxy() {
case "$1" in

View file

@ -14,8 +14,8 @@ github.com/mattn/go-shellwords a72fbe27a1b0ed0df2f027549450
github.com/sirupsen/logrus 8bdbc7bcc01dcbb8ec23dc8a28e332258d25251f # v1.4.1
github.com/tchap/go-patricia a7f0089c6f496e8e70402f61733606daa326cac5 # v2.3.0
github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3 # v0.1.0
golang.org/x/net eb5bcb51f2a31c7d5141d810b70815c05d9c9146
golang.org/x/sys 4b34438f7a67ee5f45cc6132e2bad873a20324e9
golang.org/x/net f3200d17e092c607f615320ecaad13d87ad9a2b3
golang.org/x/sys 4c4f7f33c9ed00de01c4c741d2177abfcfe19307
github.com/docker/go-units 519db1ee28dcc9fd2474ae59fca29a810482bfb1 # v0.4.0
github.com/docker/go-connections 7395e3f8aa162843a74ed6d48e79627d9792ac55 # v0.4.0
golang.org/x/text f21a4dfb5e38f5895301dc265a8def02365cc3d0 # v0.3.0
@ -39,19 +39,20 @@ github.com/gofrs/flock 7f43ea2e6a643ad441fc12d0ecc0
# libnetwork
# When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy.installer accordingly
github.com/docker/libnetwork fc5a7d91d54cc98f64fc28f9e288b46a0bee756c
github.com/docker/libnetwork 92d1fbe1eb0883cf11d283cea8e658275146411d
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
github.com/hashicorp/memberlist 3d8438da9589e7b608a83ffac1ef8211486bcb7c
github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372
github.com/hashicorp/go-sockaddr 6d291a969b86c4b633730bfc6b8b9d64c3aafed9
github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e
github.com/hashicorp/errwrap 8a6fb523712970c966eefc6b39ed2c5e74880354 # v1.0.0
github.com/hashicorp/go-sockaddr c7188e74f6acae5a989bdc959aa779f8b9f42faf # v1.0.2
github.com/hashicorp/go-multierror 886a7fbe3eb1c874d46f623bfa70af45f425b3d1 # v1.0.0
github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
github.com/docker/libkv 458977154600b9f23984d9f4b82e79570b5ae12b
github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
github.com/vishvananda/netlink b2de5d10e38ecce8607e6b438b6d174f389a004e
github.com/vishvananda/netns 7109fa855b0ff1ebef7fbd2f6aa613e8db7cfbc0
github.com/vishvananda/netlink a2ad57a690f3caf3015351d2d6e1c0b95c349752
# When updating, consider updating TOMLV_COMMIT in hack/dockerfile/install/tomlv.installer accordingly
github.com/BurntSushi/toml 3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005 # v0.3.1
@ -62,8 +63,8 @@ github.com/coreos/go-semver 8ab6407b697782a06568d4b7f1db
github.com/ugorji/go b4c50a2b199d93b13dc15e78929cfb23bfdf21ab # v1.1.1
github.com/hashicorp/consul 9a9cc9341bb487651a0399e3fc5e1e8a42e62dd9 # v0.5.2
github.com/miekg/dns e57bf427e68187a27e22adceac868350d7a7079b # v1.0.7
github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb
go.etcd.io/bbolt 7ee3ded59d4835e10f3e7d0f7603c42aa5e83820 # v1.3.1-etcd.8
github.com/ishidawataru/sctp 6e2cb1366111dcf547c13531e3a263a067715847
go.etcd.io/bbolt a0458a2b35708eef59eb5f620ceb3cd1c01a824d # v1.3.3
# get graph and distribution packages
github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580

View file

@ -89,9 +89,6 @@ func main() {
}
```
## Future
Please refer to [roadmap](ROADMAP.md) for more information.
## Contributing
Want to hack on libnetwork? [Docker's contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md) apply.

View file

@ -706,9 +706,10 @@ const overlayDSROptionString = "dsr"
// are network specific and modeled in a generic way.
func (c *controller) NewNetwork(networkType, name string, id string, options ...NetworkOption) (Network, error) {
var (
cap *driverapi.Capability
err error
t *network
cap *driverapi.Capability
err error
t *network
skipCfgEpCount bool
)
if id != "" {
@ -801,8 +802,9 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ...
if err = t.applyConfigurationTo(network); err != nil {
return nil, types.InternalErrorf("Failed to apply configuration: %v", err)
}
network.generic[netlabel.Internal] = network.internal
defer func() {
if err == nil {
if err == nil && !skipCfgEpCount {
if err := t.getEpCnt().IncEndpointCnt(); err != nil {
logrus.Warnf("Failed to update reference count for configuration network %q on creation of network %q: %v",
t.Name(), network.Name(), err)
@ -823,7 +825,13 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ...
err = c.addNetwork(network)
if err != nil {
return nil, err
if strings.Contains(err.Error(), "restoring existing network") {
// This error can be ignored and set this boolean
// value to skip a refcount increment for configOnly networks
skipCfgEpCount = true
} else {
return nil, err
}
}
defer func() {
if err != nil {
@ -1298,7 +1306,7 @@ func (c *controller) loadIPAMDriver(name string) error {
}
if err != nil {
if err == plugins.ErrNotFound {
if errors.Cause(err) == plugins.ErrNotFound {
return types.NotFoundErrorf(err.Error())
}
return err

View file

@ -1,4 +1,4 @@
// +build !arm,!ppc64,!ppc64le
// +build !arm,!ppc64,!ppc64le,!riscv64
package bridge

View file

@ -302,7 +302,7 @@ func setINC(iface string, enable bool) error {
if i == 1 {
// Rollback the rule installed on first chain
if err2 := iptables.ProgramRule(iptables.Filter, chains[0], iptables.Delete, rules[0]); err2 != nil {
logrus.Warn("Failed to rollback iptables rule after failure (%v): %v", err, err2)
logrus.Warnf("Failed to rollback iptables rule after failure (%v): %v", err, err2)
}
}
return fmt.Errorf(msg)

View file

@ -60,10 +60,14 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo
// empty parent and --internal are handled the same. Set here to update k/v
config.Internal = true
}
err = d.createNetwork(config)
foundExisting, err := d.createNetwork(config)
if err != nil {
return err
}
if foundExisting {
return types.InternalMaskableErrorf("restoring existing network %s", config.ID)
}
// update persistent db, rollback on fail
err = d.storeUpdate(config)
if err != nil {
@ -76,12 +80,18 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo
}
// createNetwork is used by new network callbacks and persistent network cache
func (d *driver) createNetwork(config *configuration) error {
func (d *driver) createNetwork(config *configuration) (bool, error) {
foundExisting := false
networkList := d.getNetworks()
for _, nw := range networkList {
if config.Parent == nw.config.Parent {
return fmt.Errorf("network %s is already using parent interface %s",
getDummyName(stringid.TruncateID(nw.config.ID)), config.Parent)
if config.ID != nw.config.ID {
return false, fmt.Errorf("network %s is already using parent interface %s",
getDummyName(stringid.TruncateID(nw.config.ID)), config.Parent)
}
logrus.Debugf("Create Network for the same ID %s\n", config.ID)
foundExisting = true
break
}
}
if !parentExists(config.Parent) {
@ -89,9 +99,10 @@ func (d *driver) createNetwork(config *configuration) error {
if config.Internal {
err := createDummyLink(config.Parent, getDummyName(stringid.TruncateID(config.ID)))
if err != nil {
return err
return false, err
}
config.CreatedSlaveLink = true
// notify the user in logs they have limited communications
if config.Parent == getDummyName(stringid.TruncateID(config.ID)) {
logrus.Debugf("Empty -o parent= and --internal flags limit communications to other containers inside of network: %s",
@ -102,22 +113,24 @@ func (d *driver) createNetwork(config *configuration) error {
// a valid example is 'eth0.10' for a parent iface 'eth0' with a vlan id '10'
err := createVlanLink(config.Parent)
if err != nil {
return err
return false, err
}
// if driver created the networks slave link, record it for future deletion
config.CreatedSlaveLink = true
}
}
n := &network{
id: config.ID,
driver: d,
endpoints: endpointTable{},
config: config,
if !foundExisting {
n := &network{
id: config.ID,
driver: d,
endpoints: endpointTable{},
config: config,
}
// add the network
d.addNetwork(n)
}
// add the *network
d.addNetwork(n)
return nil
return foundExisting, nil
}
// DeleteNetwork the network for the specified driver type
@ -182,10 +195,12 @@ func parseNetworkOptions(id string, option options.Generic) (*configuration, err
}
}
// setting the parent to "" will trigger an isolated network dummy parent link
if _, ok := option[netlabel.Internal]; ok {
config.Internal = true
// empty --parent= and --internal are handled the same.
config.Parent = ""
if val, ok := option[netlabel.Internal]; ok {
if internal, ok := val.(bool); ok && internal {
config.Internal = true
// empty --parent= and --internal are handled the same.
config.Parent = ""
}
}
return config, nil
}

View file

@ -55,7 +55,14 @@ func (d *driver) initStore(option map[string]interface{}) error {
return types.InternalErrorf("ipvlan driver failed to initialize data store: %v", err)
}
return d.populateNetworks()
err = d.populateNetworks()
if err != nil {
return err
}
err = d.populateEndpoints()
if err != nil {
return err
}
}
return nil
@ -73,7 +80,7 @@ func (d *driver) populateNetworks() error {
}
for _, kvo := range kvol {
config := kvo.(*configuration)
if err = d.createNetwork(config); err != nil {
if _, err = d.createNetwork(config); err != nil {
logrus.Warnf("could not create ipvlan network for id %s from persistent state", config.ID)
}
}

View file

@ -64,10 +64,15 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo
// empty parent and --internal are handled the same. Set here to update k/v
config.Internal = true
}
err = d.createNetwork(config)
foundExisting, err := d.createNetwork(config)
if err != nil {
return err
}
if foundExisting {
return types.InternalMaskableErrorf("restoring existing network %s", config.ID)
}
// update persistent db, rollback on fail
err = d.storeUpdate(config)
if err != nil {
@ -80,12 +85,18 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo
}
// createNetwork is used by new network callbacks and persistent network cache
func (d *driver) createNetwork(config *configuration) error {
func (d *driver) createNetwork(config *configuration) (bool, error) {
foundExisting := false
networkList := d.getNetworks()
for _, nw := range networkList {
if config.Parent == nw.config.Parent {
return fmt.Errorf("network %s is already using parent interface %s",
getDummyName(stringid.TruncateID(nw.config.ID)), config.Parent)
if config.ID != nw.config.ID {
return false, fmt.Errorf("network %s is already using parent interface %s",
getDummyName(stringid.TruncateID(nw.config.ID)), config.Parent)
}
logrus.Debugf("Create Network for the same ID %s\n", config.ID)
foundExisting = true
break
}
}
if !parentExists(config.Parent) {
@ -93,7 +104,7 @@ func (d *driver) createNetwork(config *configuration) error {
if config.Internal {
err := createDummyLink(config.Parent, getDummyName(stringid.TruncateID(config.ID)))
if err != nil {
return err
return false, err
}
config.CreatedSlaveLink = true
// notify the user in logs they have limited communications
@ -106,22 +117,24 @@ func (d *driver) createNetwork(config *configuration) error {
// a valid example is 'eth0.10' for a parent iface 'eth0' with a vlan id '10'
err := createVlanLink(config.Parent)
if err != nil {
return err
return false, err
}
// if driver created the networks slave link, record it for future deletion
config.CreatedSlaveLink = true
}
}
n := &network{
id: config.ID,
driver: d,
endpoints: endpointTable{},
config: config,
if !foundExisting {
n := &network{
id: config.ID,
driver: d,
endpoints: endpointTable{},
config: config,
}
// add the network
d.addNetwork(n)
}
// add the *network
d.addNetwork(n)
return nil
return foundExisting, nil
}
// DeleteNetwork deletes the network for the specified driver type
@ -186,10 +199,12 @@ func parseNetworkOptions(id string, option options.Generic) (*configuration, err
}
}
// setting the parent to "" will trigger an isolated network dummy parent link
if _, ok := option[netlabel.Internal]; ok {
config.Internal = true
// empty --parent= and --internal are handled the same.
config.Parent = ""
if val, ok := option[netlabel.Internal]; ok {
if internal, ok := val.(bool); ok && internal {
config.Internal = true
// empty --parent= and --internal are handled the same.
config.Parent = ""
}
}
return config, nil

View file

@ -55,7 +55,15 @@ func (d *driver) initStore(option map[string]interface{}) error {
return types.InternalErrorf("macvlan driver failed to initialize data store: %v", err)
}
return d.populateNetworks()
err = d.populateNetworks()
if err != nil {
return err
}
err = d.populateEndpoints()
if err != nil {
return err
}
}
return nil
@ -73,7 +81,7 @@ func (d *driver) populateNetworks() error {
}
for _, kvo := range kvol {
config := kvo.(*configuration)
if err = d.createNetwork(config); err != nil {
if _, err = d.createNetwork(config); err != nil {
logrus.Warnf("Could not create macvlan network for id %s from persistent state", config.ID)
}
}

View file

@ -7,9 +7,9 @@ import (
)
var ovConfig = map[string]*kernel.OSValue{
"net.ipv4.neigh.default.gc_thresh1": {"8192", checkHigher},
"net.ipv4.neigh.default.gc_thresh2": {"49152", checkHigher},
"net.ipv4.neigh.default.gc_thresh3": {"65536", checkHigher},
"net.ipv4.neigh.default.gc_thresh1": {Value: "8192", CheckFn: checkHigher},
"net.ipv4.neigh.default.gc_thresh2": {Value: "49152", CheckFn: checkHigher},
"net.ipv4.neigh.default.gc_thresh3": {Value: "65536", CheckFn: checkHigher},
}
func checkHigher(val1, val2 string) bool {

View file

@ -12,7 +12,6 @@ import (
"strconv"
"strings"
"sync"
"syscall"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/libnetwork/datastore"
@ -27,6 +26,7 @@ import (
"github.com/vishvananda/netlink"
"github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
)
var (
@ -97,18 +97,18 @@ func setDefaultVlan() {
}
// make sure the sysfs mount doesn't propagate back
if err = syscall.Unshare(syscall.CLONE_NEWNS); err != nil {
if err = unix.Unshare(unix.CLONE_NEWNS); err != nil {
logrus.Errorf("unshare failed, %v", err)
os.Exit(1)
}
flag := syscall.MS_PRIVATE | syscall.MS_REC
if err = syscall.Mount("", "/", "", uintptr(flag), ""); err != nil {
flag := unix.MS_PRIVATE | unix.MS_REC
if err = unix.Mount("", "/", "", uintptr(flag), ""); err != nil {
logrus.Errorf("root mount failed, %v", err)
os.Exit(1)
}
if err = syscall.Mount("sysfs", "/sys", "sysfs", 0, ""); err != nil {
if err = unix.Mount("sysfs", "/sys", "sysfs", 0, ""); err != nil {
logrus.Errorf("mounting sysfs failed, %v", err)
os.Exit(1)
}
@ -427,7 +427,7 @@ func populateVNITbl() {
}
defer ns.Close()
nlh, err := netlink.NewHandleAt(ns, syscall.NETLINK_ROUTE)
nlh, err := netlink.NewHandleAt(ns, unix.NETLINK_ROUTE)
if err != nil {
logrus.Errorf("Could not open netlink handle during vni population for ns %s: %v", path, err)
return nil
@ -583,7 +583,7 @@ func (n *network) setupSubnetSandbox(s *subnet, brName, vxlanName string) error
if ok {
deleteVxlanByVNI(path, s.vni)
if err := syscall.Unmount(path, syscall.MNT_FORCE); err != nil {
if err := unix.Unmount(path, unix.MNT_FORCE); err != nil {
logrus.Errorf("unmount of %s failed: %v", path, err)
}
os.Remove(path)
@ -693,7 +693,7 @@ func (n *network) cleanupStaleSandboxes() {
if strings.Contains(n.id, pattern) {
// Delete all vnis
deleteVxlanByVNI(path, 0)
syscall.Unmount(path, syscall.MNT_DETACH)
unix.Unmount(path, unix.MNT_DETACH)
os.Remove(path)
// Now that we have destroyed this
@ -755,12 +755,12 @@ func (n *network) initSandbox(restore bool) error {
var nlSock *nl.NetlinkSocket
sbox.InvokeFunc(func() {
nlSock, err = nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_NEIGH)
nlSock, err = nl.Subscribe(unix.NETLINK_ROUTE, unix.RTNLGRP_NEIGH)
if err != nil {
return
}
// set the receive timeout to not remain stuck on the RecvFrom if the fd gets closed
tv := syscall.NsecToTimeval(soTimeout.Nanoseconds())
tv := unix.NsecToTimeval(soTimeout.Nanoseconds())
err = nlSock.SetReceiveTimeout(&tv)
})
n.nlSocket = nlSock
@ -803,7 +803,7 @@ func (n *network) watchMiss(nlSock *nl.NetlinkSocket, nsPath string) {
return
}
// When the receive timeout expires the receive will return EAGAIN
if err == syscall.EAGAIN {
if err == unix.EAGAIN {
// we continue here to avoid spam for timeouts
continue
}
@ -812,7 +812,7 @@ func (n *network) watchMiss(nlSock *nl.NetlinkSocket, nsPath string) {
}
for _, msg := range msgs {
if msg.Header.Type != syscall.RTM_GETNEIGH && msg.Header.Type != syscall.RTM_NEWNEIGH {
if msg.Header.Type != unix.RTM_GETNEIGH && msg.Header.Type != unix.RTM_NEWNEIGH {
continue
}

View file

@ -111,7 +111,10 @@ const (
// IsBuiltinLocalDriver validates if network-type is a builtin local-scoped driver
func IsBuiltinLocalDriver(networkType string) bool {
if "l2bridge" == networkType || "l2tunnel" == networkType || "nat" == networkType || "ics" == networkType || "transparent" == networkType {
if "l2bridge" == networkType || "l2tunnel" == networkType ||
"nat" == networkType || "ics" == networkType ||
"transparent" == networkType || "internal" == networkType ||
"private" == networkType {
return true
}
@ -433,7 +436,7 @@ func convertQosPolicies(qosPolicies []types.QosPolicy) ([]json.RawMessage, error
// understood by the HCS.
for _, elem := range qosPolicies {
encodedPolicy, err := json.Marshal(hcsshim.QosPolicy{
Type: "QOS",
Type: "QOS",
MaximumOutgoingBandwidthInBytes: elem.MaxEgressBandwidth,
})

View file

@ -16,6 +16,8 @@ func getInitializers(experimental bool) []initializer {
{windows.GetInit("l2bridge"), "l2bridge"},
{windows.GetInit("l2tunnel"), "l2tunnel"},
{windows.GetInit("nat"), "nat"},
{windows.GetInit("internal"), "internal"},
{windows.GetInit("private"), "private"},
{windows.GetInit("ics"), "ics"},
}
}

View file

@ -2,6 +2,7 @@ package libnetwork
import (
"github.com/docker/libnetwork/iptables"
"github.com/docker/libnetwork/netlabel"
"github.com/sirupsen/logrus"
)
@ -9,15 +10,44 @@ const userChain = "DOCKER-USER"
func (c *controller) arrangeUserFilterRule() {
c.Lock()
arrangeUserFilterRule()
if c.hasIPTablesEnabled() {
arrangeUserFilterRule()
}
c.Unlock()
iptables.OnReloaded(func() {
c.Lock()
arrangeUserFilterRule()
if c.hasIPTablesEnabled() {
arrangeUserFilterRule()
}
c.Unlock()
})
}
func (c *controller) hasIPTablesEnabled() bool {
// Locking c should be handled in the calling method.
if c.cfg == nil || c.cfg.Daemon.DriverCfg[netlabel.GenericData] == nil {
return false
}
genericData, ok := c.cfg.Daemon.DriverCfg[netlabel.GenericData]
if !ok {
return false
}
optMap := genericData.(map[string]interface{})
enabled, ok := optMap["EnableIPTables"].(bool)
if !ok {
return false
}
return enabled
}
// This chain allow users to configure firewall policies in a way that persists
// docker operations/restarts. Docker will not delete or modify any pre-existing
// rules from the DOCKER-USER filter chain.

View file

@ -72,11 +72,13 @@ func (e ChainError) Error() string {
}
func probe() {
if out, err := exec.Command("modprobe", "-va", "nf_nat").CombinedOutput(); err != nil {
logrus.Warnf("Running modprobe nf_nat failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
path, err := exec.LookPath("iptables")
if err != nil {
logrus.Warnf("Failed to find iptables: %v", err)
return
}
if out, err := exec.Command("modprobe", "-va", "xt_conntrack").CombinedOutput(); err != nil {
logrus.Warnf("Running modprobe xt_conntrack failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
if out, err := exec.Command(path, "--wait", "-t", "nat", "-L", "-n").CombinedOutput(); err != nil {
logrus.Warnf("Running iptables --wait -t nat -L -n failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
}
}

View file

@ -3,14 +3,13 @@
package ipvs
import (
"net"
"syscall"
"time"
"fmt"
"net"
"time"
"github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
)
const (
@ -98,16 +97,16 @@ func New(path string) (*Handle, error) {
}
defer n.Close()
sock, err := nl.GetNetlinkSocketAt(n, netns.None(), syscall.NETLINK_GENERIC)
sock, err := nl.GetNetlinkSocketAt(n, netns.None(), unix.NETLINK_GENERIC)
if err != nil {
return nil, err
}
// Add operation timeout to avoid deadlocks
tv := syscall.NsecToTimeval(netlinkSendSocketTimeout.Nanoseconds())
tv := unix.NsecToTimeval(netlinkSendSocketTimeout.Nanoseconds())
if err := sock.SetSendTimeout(&tv); err != nil {
return nil, err
}
tv = syscall.NsecToTimeval(netlinkRecvSocketsTimeout.Nanoseconds())
tv = unix.NsecToTimeval(netlinkRecvSocketsTimeout.Nanoseconds())
if err := sock.SetReceiveTimeout(&tv); err != nil {
return nil, err
}

View file

@ -315,6 +315,7 @@ func assembleStats(msg []byte) (SvcStats, error) {
func assembleService(attrs []syscall.NetlinkRouteAttr) (*Service, error) {
var s Service
var addressBytes []byte
for _, attr := range attrs {
@ -327,11 +328,7 @@ func assembleService(attrs []syscall.NetlinkRouteAttr) (*Service, error) {
case ipvsSvcAttrProtocol:
s.Protocol = native.Uint16(attr.Value)
case ipvsSvcAttrAddress:
ip, err := parseIP(attr.Value, s.AddressFamily)
if err != nil {
return nil, err
}
s.Address = ip
addressBytes = attr.Value
case ipvsSvcAttrPort:
s.Port = binary.BigEndian.Uint16(attr.Value)
case ipvsSvcAttrFWMark:
@ -353,6 +350,16 @@ func assembleService(attrs []syscall.NetlinkRouteAttr) (*Service, error) {
}
}
// parse Address after parse AddressFamily incase of parseIP error
if addressBytes != nil {
ip, err := parseIP(addressBytes, s.AddressFamily)
if err != nil {
return nil, err
}
s.Address = ip
}
return &s, nil
}
@ -416,18 +423,18 @@ func (i *Handle) doCmdWithoutAttr(cmd uint8) ([][]byte, error) {
func assembleDestination(attrs []syscall.NetlinkRouteAttr) (*Destination, error) {
var d Destination
var addressBytes []byte
for _, attr := range attrs {
attrType := int(attr.Attr.Type)
switch attrType {
case ipvsDestAttrAddressFamily:
d.AddressFamily = native.Uint16(attr.Value)
case ipvsDestAttrAddress:
ip, err := parseIP(attr.Value, syscall.AF_INET)
if err != nil {
return nil, err
}
d.Address = ip
addressBytes = attr.Value
case ipvsDestAttrPort:
d.Port = binary.BigEndian.Uint16(attr.Value)
case ipvsDestAttrForwardingMethod:
@ -438,8 +445,6 @@ func assembleDestination(attrs []syscall.NetlinkRouteAttr) (*Destination, error)
d.UpperThreshold = native.Uint32(attr.Value)
case ipvsDestAttrLowerThreshold:
d.LowerThreshold = native.Uint32(attr.Value)
case ipvsDestAttrAddressFamily:
d.AddressFamily = native.Uint16(attr.Value)
case ipvsDestAttrActiveConnections:
d.ActiveConnections = int(native.Uint16(attr.Value))
case ipvsDestAttrInactiveConnections:
@ -452,6 +457,16 @@ func assembleDestination(attrs []syscall.NetlinkRouteAttr) (*Destination, error)
d.Stats = DstStats(stats)
}
}
// parse Address after parse AddressFamily incase of parseIP error
if addressBytes != nil {
ip, err := parseIP(addressBytes, d.AddressFamily)
if err != nil {
return nil, err
}
d.Address = ip
}
return &d, nil
}

View file

@ -1054,7 +1054,7 @@ func (n *network) delete(force bool, rmLBEndpoint bool) error {
t.Name(), n.Name(), err)
}
} else {
logrus.Warnf("Could not find configuration network %q during removal of network %q", n.configOnly, n.Name())
logrus.Warnf("Could not find configuration network %q during removal of network %q", n.configFrom, n.Name())
}
}
@ -1381,14 +1381,18 @@ func delIPToName(ipMap setmatrix.SetMatrix, name, serviceID string, ip net.IP) {
}
func addNameToIP(svcMap setmatrix.SetMatrix, name, serviceID string, epIP net.IP) {
svcMap.Insert(name, svcMapEntry{
// Since DNS name resolution is case-insensitive, Use the lower-case form
// of the name as the key into svcMap
lowerCaseName := strings.ToLower(name)
svcMap.Insert(lowerCaseName, svcMapEntry{
ip: epIP.String(),
serviceID: serviceID,
})
}
func delNameToIP(svcMap setmatrix.SetMatrix, name, serviceID string, epIP net.IP) {
svcMap.Remove(name, svcMapEntry{
lowerCaseName := strings.ToLower(name)
svcMap.Remove(lowerCaseName, svcMapEntry{
ip: epIP.String(),
serviceID: serviceID,
})
@ -1956,6 +1960,7 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
}
req = strings.TrimSuffix(req, ".")
req = strings.ToLower(req)
ipSet, ok := sr.svcMap.Get(req)
if ipType == types.IPv6 {

View file

@ -76,12 +76,8 @@ func NlHandle() *netlink.Handle {
func getSupportedNlFamilies() []int {
fams := []int{syscall.NETLINK_ROUTE}
// NETLINK_XFRM test
if err := loadXfrmModules(); err != nil {
if checkXfrmSocket() != nil {
logrus.Warnf("Could not load necessary modules for IPSEC rules: %v", err)
} else {
fams = append(fams, syscall.NETLINK_XFRM)
}
if err := checkXfrmSocket(); err != nil {
logrus.Warnf("Could not load necessary modules for IPSEC rules: %v", err)
} else {
fams = append(fams, syscall.NETLINK_XFRM)
}
@ -99,16 +95,6 @@ func getSupportedNlFamilies() []int {
return fams
}
func loadXfrmModules() error {
if out, err := exec.Command("modprobe", "-va", "xfrm_user").CombinedOutput(); err != nil {
return fmt.Errorf("Running modprobe xfrm_user failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
}
if out, err := exec.Command("modprobe", "-va", "xfrm_algo").CombinedOutput(); err != nil {
return fmt.Errorf("Running modprobe xfrm_algo failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
}
return nil
}
// API check on required xfrm modules (xfrm_user, xfrm_algo)
func checkXfrmSocket() error {
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_XFRM)

View file

@ -40,7 +40,7 @@ var (
loadBalancerConfig = map[string]*kernel.OSValue{
// expires connection from the IPVS connection table when the backend is not available
// more info: https://github.com/torvalds/linux/blob/master/Documentation/networking/ipvs-sysctl.txt#L126:1
"net.ipv4.vs.expire_nodest_conn": {"1", nil},
"net.ipv4.vs.expire_nodest_conn": {Value: "1", CheckFn: nil},
}
)

View file

@ -115,16 +115,16 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
m = &mapping{
proto: proto,
host: &sctp.SCTPAddr{IP: []net.IP{hostIP}, Port: allocatedHostPort},
host: &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: hostIP}}, Port: allocatedHostPort},
container: container,
}
if useProxy {
sctpAddr := container.(*sctp.SCTPAddr)
if len(sctpAddr.IP) == 0 {
if len(sctpAddr.IPAddrs) == 0 {
return nil, ErrSCTPAddrNoIP
}
m.userlandProxy, err = newProxy(proto, hostIP, allocatedHostPort, sctpAddr.IP[0], sctpAddr.Port, pm.proxyPath)
m.userlandProxy, err = newProxy(proto, hostIP, allocatedHostPort, sctpAddr.IPAddrs[0].IP, sctpAddr.Port, pm.proxyPath)
if err != nil {
return nil, err
}
@ -210,10 +210,10 @@ func (pm *PortMapper) Unmap(host net.Addr) error {
case *net.UDPAddr:
return pm.Allocator.ReleasePort(a.IP, "udp", a.Port)
case *sctp.SCTPAddr:
if len(a.IP) == 0 {
if len(a.IPAddrs) == 0 {
return ErrSCTPAddrNoIP
}
return pm.Allocator.ReleasePort(a.IP[0], "sctp", a.Port)
return pm.Allocator.ReleasePort(a.IPAddrs[0].IP, "sctp", a.Port)
}
return ErrUnknownBackendAddressType
}
@ -239,11 +239,11 @@ func getKey(a net.Addr) string {
case *net.UDPAddr:
return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "udp")
case *sctp.SCTPAddr:
if len(t.IP) == 0 {
if len(t.IPAddrs) == 0 {
logrus.Error(ErrSCTPAddrNoIP)
return ""
}
return fmt.Sprintf("%s:%d/%s", t.IP[0].String(), t.Port, "sctp")
return fmt.Sprintf("%s:%d/%s", t.IPAddrs[0].IP.String(), t.Port, "sctp")
}
return ""
}
@ -255,11 +255,11 @@ func getIPAndPort(a net.Addr) (net.IP, int) {
case *net.UDPAddr:
return t.IP, t.Port
case *sctp.SCTPAddr:
if len(t.IP) == 0 {
if len(t.IPAddrs) == 0 {
logrus.Error(ErrSCTPAddrNoIP)
return nil, 0
}
return t.IP[0], t.Port
return t.IPAddrs[0].IP, t.Port
}
return nil, 0
}

View file

@ -90,7 +90,7 @@ func newDummyProxy(proto string, hostIP net.IP, hostPort int) (userlandProxy, er
addr := &net.UDPAddr{IP: hostIP, Port: hostPort}
return &dummyProxy{addr: addr}, nil
case "sctp":
addr := &sctp.SCTPAddr{IP: []net.IP{hostIP}, Port: hostPort}
addr := &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: hostIP}}, Port: hostPort}
return &dummyProxy{addr: addr}, nil
default:
return nil, fmt.Errorf("Unknown addr type: %s", proto)

View file

@ -366,8 +366,8 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
if query == nil || len(query.Question) == 0 {
return
}
name := query.Question[0].Name
name := query.Question[0].Name
switch query.Question[0].Qtype {
case dns.TypeA:
resp, err = r.handleIPQuery(name, query, types.IPv4)

View file

@ -99,7 +99,7 @@ func (p PortBinding) HostAddr() (net.Addr, error) {
case TCP:
return &net.TCPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
case SCTP:
return &sctp.SCTPAddr{IP: []net.IP{p.HostIP}, Port: int(p.HostPort)}, nil
return &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: p.HostIP}}, Port: int(p.HostPort)}, nil
default:
return nil, ErrInvalidProtocolBinding(p.Proto.String())
}
@ -113,7 +113,7 @@ func (p PortBinding) ContainerAddr() (net.Addr, error) {
case TCP:
return &net.TCPAddr{IP: p.IP, Port: int(p.Port)}, nil
case SCTP:
return &sctp.SCTPAddr{IP: []net.IP{p.IP}, Port: int(p.Port)}, nil
return &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: p.IP}}, Port: int(p.Port)}, nil
default:
return nil, ErrInvalidProtocolBinding(p.Proto.String())
}

View file

@ -1,50 +1,55 @@
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
github.com/Microsoft/go-winio v0.4.11
github.com/Microsoft/hcsshim v0.7.3
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
github.com/codegangsta/cli a65b733b303f0055f8d324d805f393cd3e7a7904
github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b
github.com/coreos/etcd v3.2.1
github.com/coreos/go-semver v0.2.0
github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
go.etcd.io/bbolt v1.3.1-etcd.8
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
github.com/BurntSushi/toml 3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005 # v0.3.1
github.com/Microsoft/go-winio c599b533b43b1363d7d7c6cfda5ede70ed73ff13
github.com/Microsoft/hcsshim ba3d6667710fa905116f39a19d059c4c1016be7c
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
github.com/codegangsta/cli a65b733b303f0055f8d324d805f393cd3e7a7904
github.com/containerd/continuity 004b46473808b3e7a4a3049c20e4376c91eb966d
github.com/coreos/etcd fca8add78a9d926166eb739b8e4a124434025ba3 # v3.3.9
github.com/coreos/go-semver 8ab6407b697782a06568d4b7f1db25550ec2e4c6 # v0.2.0
github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
go.etcd.io/bbolt 7ee3ded59d4835e10f3e7d0f7603c42aa5e83820 # v1.3.1-etcd.8
github.com/docker/docker 162ba6016def672690ee4a1f3978368853a1e149
github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
github.com/docker/libkv 458977154600b9f23984d9f4b82e79570b5ae12b
github.com/docker/docker dbe4a30928d418e0570891a09703bcbc0e4997a1
github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580
github.com/docker/go-connections 7395e3f8aa162843a74ed6d48e79627d9792ac55 # v0.4.0
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/docker/go-units 47565b4f722fb6ceae66b95f853feed578a4a51c # v0.3.3
github.com/docker/libkv 458977154600b9f23984d9f4b82e79570b5ae12b
github.com/godbus/dbus v4.0.0
github.com/gogo/protobuf v1.0.0
github.com/gorilla/context v1.1
github.com/gorilla/mux v1.1
github.com/hashicorp/consul v0.5.2
github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e
github.com/hashicorp/memberlist 3d8438da9589e7b608a83ffac1ef8211486bcb7c
github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372
github.com/hashicorp/go-sockaddr 6d291a969b86c4b633730bfc6b8b9d64c3aafed9
github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
github.com/mattn/go-shellwords v1.0.3
github.com/miekg/dns v1.0.7
github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/runc 96ec2177ae841256168fcf76954f7177af9446eb
github.com/opencontainers/runtime-spec v1.0.1
github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
github.com/sirupsen/logrus v1.0.3
github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
github.com/vishvananda/netlink b2de5d10e38ecce8607e6b438b6d174f389a004e
github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
golang.org/x/crypto 1a580b3eff7814fc9b40602fd35256c63b50f491
golang.org/x/net 0ed95abb35c445290478a5348a7b38bb154135fd
golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd
golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb
github.com/gogo/protobuf ba06b47c162d49f2af050fb4c75bcbc86a159d5c # v1.2.1
github.com/golang/protobuf aa810b61a9c79d51363740d207bb46cf8e620ed5 # v1.2.0
google.golang.org/grpc 7a6a684ca69eb4cae85ad0a484f2e531598c047b # v1.12.2
google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9
gotest.tools v2.1.0
github.com/google/go-cmp v0.2.0
github.com/godbus/dbus 5f6efc7ef2759c81b7ba876593971bfce311eab3 # v4.0.0
github.com/gorilla/mux c5c6c98bc25355028a63748a498942a6398ccd22 # v1.7.1
github.com/hashicorp/consul 9a9cc9341bb487651a0399e3fc5e1e8a42e62dd9 # v0.5.2
github.com/hashicorp/errwrap 8a6fb523712970c966eefc6b39ed2c5e74880354 # v1.0.0
github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
github.com/hashicorp/go-multierror 886a7fbe3eb1c874d46f623bfa70af45f425b3d1 # v1.0.0
github.com/hashicorp/memberlist 3d8438da9589e7b608a83ffac1ef8211486bcb7c
github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372
github.com/hashicorp/go-sockaddr c7188e74f6acae5a989bdc959aa779f8b9f42faf # v1.0.2
github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
github.com/mattn/go-shellwords 02e3cf038dcea8290e44424da473dd12be796a8a # v1.0.3
github.com/miekg/dns e57bf427e68187a27e22adceac868350d7a7079b # v1.0.7
github.com/opencontainers/go-digest 279bed98673dd5bef374d3b6e4b09e2af76183bf # v1.0.0-rc1
github.com/opencontainers/image-spec d60099175f88c47cd379c4738d158884749ed235 # v1.0.1
github.com/opencontainers/runc 2b18fe1d885ee5083ef9f0838fee39b62d653e30
github.com/opencontainers/runtime-spec 29686dbc5559d93fb1ef402eeda3e35c38d75af4 # v1.0.1-59-g29686db
github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
github.com/sirupsen/logrus f006c2ac4710855cf0f916dd6b77acf6b048dc6e # v1.0.3
github.com/ugorji/go b4c50a2b199d93b13dc15e78929cfb23bfdf21ab # v1.1.1
github.com/vishvananda/netlink a2ad57a690f3caf3015351d2d6e1c0b95c349752 # v1.0.0
github.com/vishvananda/netns 7109fa855b0ff1ebef7fbd2f6aa613e8db7cfbc0
golang.org/x/crypto b7391e95e576cacdcdd422573063bc057239113d
golang.org/x/net a680a1efc54dd51c040b3b5ce4939ea3cf2ea0d1
golang.org/x/sys d455e41777fca6e8a5a79e34a14b8368bc11d9ba
golang.org/x/sync 1d60e4601c6fd243af51cc01ddf169918a5407ca
github.com/pkg/errors ba968bfe8b2f7e042a574c888954fccecfa385b4 # v0.8.1
github.com/ishidawataru/sctp 6e2cb1366111dcf547c13531e3a263a067715847
gotest.tools b6e20af1ed078cd01a6413b734051a292450b4cb # v2.1.0
github.com/google/go-cmp 3af367b6b30c263d47e8895973edcca9a49cf029 # v0.2.0

354
vendor/github.com/hashicorp/errwrap/LICENSE generated vendored Normal file
View file

@ -0,0 +1,354 @@
Mozilla Public License, version 2.0
1. Definitions
1.1. “Contributor”
means each individual or legal entity that creates, contributes to the
creation of, or owns Covered Software.
1.2. “Contributor Version”
means the combination of the Contributions of others (if any) used by a
Contributor and that particular Contributors Contribution.
1.3. “Contribution”
means Covered Software of a particular Contributor.
1.4. “Covered Software”
means Source Code Form to which the initial Contributor has attached the
notice in Exhibit A, the Executable Form of such Source Code Form, and
Modifications of such Source Code Form, in each case including portions
thereof.
1.5. “Incompatible With Secondary Licenses”
means
a. that the initial Contributor has attached the notice described in
Exhibit B to the Covered Software; or
b. that the Covered Software was made available under the terms of version
1.1 or earlier of the License, but not also under the terms of a
Secondary License.
1.6. “Executable Form”
means any form of the work other than Source Code Form.
1.7. “Larger Work”
means a work that combines Covered Software with other material, in a separate
file or files, that is not Covered Software.
1.8. “License”
means this document.
1.9. “Licensable”
means having the right to grant, to the maximum extent possible, whether at the
time of the initial grant or subsequently, any and all of the rights conveyed by
this License.
1.10. “Modifications”
means any of the following:
a. any file in Source Code Form that results from an addition to, deletion
from, or modification of the contents of Covered Software; or
b. any new file in Source Code Form that contains any Covered Software.
1.11. “Patent Claims” of a Contributor
means any patent claim(s), including without limitation, method, process,
and apparatus claims, in any patent Licensable by such Contributor that
would be infringed, but for the grant of the License, by the making,
using, selling, offering for sale, having made, import, or transfer of
either its Contributions or its Contributor Version.
1.12. “Secondary License”
means either the GNU General Public License, Version 2.0, the GNU Lesser
General Public License, Version 2.1, the GNU Affero General Public
License, Version 3.0, or any later versions of those licenses.
1.13. “Source Code Form”
means the form of the work preferred for making modifications.
1.14. “You” (or “Your”)
means an individual or a legal entity exercising rights under this
License. For legal entities, “You” includes any entity that controls, is
controlled by, or is under common control with You. For purposes of this
definition, “control” means (a) the power, direct or indirect, to cause
the direction or management of such entity, whether by contract or
otherwise, or (b) ownership of more than fifty percent (50%) of the
outstanding shares or beneficial ownership of such entity.
2. License Grants and Conditions
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
a. under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or as
part of a Larger Work; and
b. under Patent Claims of such Contributor to make, use, sell, offer for
sale, have made, import, and otherwise transfer either its Contributions
or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution become
effective for each Contribution on the date the Contributor first distributes
such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under this
License. No additional rights or licenses will be implied from the distribution
or licensing of Covered Software under this License. Notwithstanding Section
2.1(b) above, no patent license is granted by a Contributor:
a. for any code that a Contributor has removed from Covered Software; or
b. for infringements caused by: (i) Your and any other third partys
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
c. under Patent Claims infringed by Covered Software in the absence of its
Contributions.
This License does not grant any rights in the trademarks, service marks, or
logos of any Contributor (except as may be necessary to comply with the
notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this License
(see Section 10.2) or under the terms of a Secondary License (if permitted
under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its Contributions
are its original creation(s) or it has sufficient rights to grant the
rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under applicable
copyright doctrines of fair use, fair dealing, or other equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
Section 2.1.
3. Responsibilities
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under the
terms of this License. You must inform recipients that the Source Code Form
of the Covered Software is governed by the terms of this License, and how
they can obtain a copy of this License. You may not attempt to alter or
restrict the recipients rights in the Source Code Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
a. such Covered Software must also be made available in Source Code Form,
as described in Section 3.1, and You must inform recipients of the
Executable Form how they can obtain a copy of such Source Code Form by
reasonable means in a timely manner, at a charge no more than the cost
of distribution to the recipient; and
b. You may distribute such Executable Form under the terms of this License,
or sublicense it under different terms, provided that the license for
the Executable Form does not attempt to limit or alter the recipients
rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for the
Covered Software. If the Larger Work is a combination of Covered Software
with a work governed by one or more Secondary Licenses, and the Covered
Software is not Incompatible With Secondary Licenses, this License permits
You to additionally distribute such Covered Software under the terms of
such Secondary License(s), so that the recipient of the Larger Work may, at
their option, further distribute the Covered Software under the terms of
either this License or such Secondary License(s).
3.4. Notices
You may not remove or alter the substance of any license notices (including
copyright notices, patent notices, disclaimers of warranty, or limitations
of liability) contained within the Source Code Form of the Covered
Software, except that You may alter any license notices to the extent
required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on behalf
of any Contributor. You must make it absolutely clear that any such
warranty, support, indemnity, or liability obligation is offered by You
alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
If it is impossible for You to comply with any of the terms of this License
with respect to some or all of the Covered Software due to statute, judicial
order, or regulation then You must: (a) comply with the terms of this License
to the maximum extent possible; and (b) describe the limitations and the code
they affect. Such description must be placed in a text file included with all
distributions of the Covered Software under this License. Except to the
extent prohibited by statute or regulation, such description must be
sufficiently detailed for a recipient of ordinary skill to be able to
understand it.
5. Termination
5.1. The rights granted under this License will terminate automatically if You
fail to comply with any of its terms. However, if You become compliant,
then the rights granted under this License from a particular Contributor
are reinstated (a) provisionally, unless and until such Contributor
explicitly and finally terminates Your grants, and (b) on an ongoing basis,
if such Contributor fails to notify You of the non-compliance by some
reasonable means prior to 60 days after You have come back into compliance.
Moreover, Your grants from a particular Contributor are reinstated on an
ongoing basis if such Contributor notifies You of the non-compliance by
some reasonable means, this is the first time You have received notice of
non-compliance with this License from such Contributor, and You become
compliant prior to 30 days after Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions, counter-claims,
and cross-claims) alleging that a Contributor Version directly or
indirectly infringes any patent, then the rights granted to You by any and
all Contributors for the Covered Software under Section 2.1 of this License
shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
license agreements (excluding distributors and resellers) which have been
validly granted by You or Your distributors under this License prior to
termination shall survive termination.
6. Disclaimer of Warranty
Covered Software is provided under this License on an “as is” basis, without
warranty of any kind, either expressed, implied, or statutory, including,
without limitation, warranties that the Covered Software is free of defects,
merchantable, fit for a particular purpose or non-infringing. The entire
risk as to the quality and performance of the Covered Software is with You.
Should any Covered Software prove defective in any respect, You (not any
Contributor) assume the cost of any necessary servicing, repair, or
correction. This disclaimer of warranty constitutes an essential part of this
License. No use of any Covered Software is authorized under this License
except under this disclaimer.
7. Limitation of Liability
Under no circumstances and under no legal theory, whether tort (including
negligence), contract, or otherwise, shall any Contributor, or anyone who
distributes Covered Software as permitted above, be liable to You for any
direct, indirect, special, incidental, or consequential damages of any
character including, without limitation, damages for lost profits, loss of
goodwill, work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses, even if such party shall have been
informed of the possibility of such damages. This limitation of liability
shall not apply to liability for death or personal injury resulting from such
partys negligence to the extent applicable law prohibits such limitation.
Some jurisdictions do not allow the exclusion or limitation of incidental or
consequential damages, so this exclusion and limitation may not apply to You.
8. Litigation
Any litigation relating to this License may be brought only in the courts of
a jurisdiction where the defendant maintains its principal place of business
and such litigation shall be governed by laws of that jurisdiction, without
reference to its conflict-of-law provisions. Nothing in this Section shall
prevent a partys ability to bring cross-claims or counter-claims.
9. Miscellaneous
This License represents the complete agreement concerning the subject matter
hereof. If any provision of this License is held to be unenforceable, such
provision shall be reformed only to the extent necessary to make it
enforceable. Any law or regulation which provides that the language of a
contract shall be construed against the drafter shall not be used to construe
this License against a Contributor.
10. Versions of the License
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version of
the License under which You originally received the Covered Software, or
under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a modified
version of this License if you rename the license and remove any
references to the name of the license steward (except to note that such
modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file, then
You may include the notice in a location (such as a LICENSE file in a relevant
directory) where a recipient would be likely to look for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - “Incompatible With Secondary Licenses” Notice
This Source Code Form is “Incompatible
With Secondary Licenses”, as defined by
the Mozilla Public License, v. 2.0.

89
vendor/github.com/hashicorp/errwrap/README.md generated vendored Normal file
View file

@ -0,0 +1,89 @@
# errwrap
`errwrap` is a package for Go that formalizes the pattern of wrapping errors
and checking if an error contains another error.
There is a common pattern in Go of taking a returned `error` value and
then wrapping it (such as with `fmt.Errorf`) before returning it. The problem
with this pattern is that you completely lose the original `error` structure.
Arguably the _correct_ approach is that you should make a custom structure
implementing the `error` interface, and have the original error as a field
on that structure, such [as this example](http://golang.org/pkg/os/#PathError).
This is a good approach, but you have to know the entire chain of possible
rewrapping that happens, when you might just care about one.
`errwrap` formalizes this pattern (it doesn't matter what approach you use
above) by giving a single interface for wrapping errors, checking if a specific
error is wrapped, and extracting that error.
## Installation and Docs
Install using `go get github.com/hashicorp/errwrap`.
Full documentation is available at
http://godoc.org/github.com/hashicorp/errwrap
## Usage
#### Basic Usage
Below is a very basic example of its usage:
```go
// A function that always returns an error, but wraps it, like a real
// function might.
func tryOpen() error {
_, err := os.Open("/i/dont/exist")
if err != nil {
return errwrap.Wrapf("Doesn't exist: {{err}}", err)
}
return nil
}
func main() {
err := tryOpen()
// We can use the Contains helpers to check if an error contains
// another error. It is safe to do this with a nil error, or with
// an error that doesn't even use the errwrap package.
if errwrap.Contains(err, "does not exist") {
// Do something
}
if errwrap.ContainsType(err, new(os.PathError)) {
// Do something
}
// Or we can use the associated `Get` functions to just extract
// a specific error. This would return nil if that specific error doesn't
// exist.
perr := errwrap.GetType(err, new(os.PathError))
}
```
#### Custom Types
If you're already making custom types that properly wrap errors, then
you can get all the functionality of `errwraps.Contains` and such by
implementing the `Wrapper` interface with just one function. Example:
```go
type AppError {
Code ErrorCode
Err error
}
func (e *AppError) WrappedErrors() []error {
return []error{e.Err}
}
```
Now this works:
```go
err := &AppError{Err: fmt.Errorf("an error")}
if errwrap.ContainsType(err, fmt.Errorf("")) {
// This will work!
}
```

169
vendor/github.com/hashicorp/errwrap/errwrap.go generated vendored Normal file
View file

@ -0,0 +1,169 @@
// Package errwrap implements methods to formalize error wrapping in Go.
//
// All of the top-level functions that take an `error` are built to be able
// to take any error, not just wrapped errors. This allows you to use errwrap
// without having to type-check and type-cast everywhere.
package errwrap
import (
"errors"
"reflect"
"strings"
)
// WalkFunc is the callback called for Walk.
type WalkFunc func(error)
// Wrapper is an interface that can be implemented by custom types to
// have all the Contains, Get, etc. functions in errwrap work.
//
// When Walk reaches a Wrapper, it will call the callback for every
// wrapped error in addition to the wrapper itself. Since all the top-level
// functions in errwrap use Walk, this means that all those functions work
// with your custom type.
type Wrapper interface {
WrappedErrors() []error
}
// Wrap defines that outer wraps inner, returning an error type that
// can be cleanly used with the other methods in this package, such as
// Contains, GetAll, etc.
//
// This function won't modify the error message at all (the outer message
// will be used).
func Wrap(outer, inner error) error {
return &wrappedError{
Outer: outer,
Inner: inner,
}
}
// Wrapf wraps an error with a formatting message. This is similar to using
// `fmt.Errorf` to wrap an error. If you're using `fmt.Errorf` to wrap
// errors, you should replace it with this.
//
// format is the format of the error message. The string '{{err}}' will
// be replaced with the original error message.
func Wrapf(format string, err error) error {
outerMsg := "<nil>"
if err != nil {
outerMsg = err.Error()
}
outer := errors.New(strings.Replace(
format, "{{err}}", outerMsg, -1))
return Wrap(outer, err)
}
// Contains checks if the given error contains an error with the
// message msg. If err is not a wrapped error, this will always return
// false unless the error itself happens to match this msg.
func Contains(err error, msg string) bool {
return len(GetAll(err, msg)) > 0
}
// ContainsType checks if the given error contains an error with
// the same concrete type as v. If err is not a wrapped error, this will
// check the err itself.
func ContainsType(err error, v interface{}) bool {
return len(GetAllType(err, v)) > 0
}
// Get is the same as GetAll but returns the deepest matching error.
func Get(err error, msg string) error {
es := GetAll(err, msg)
if len(es) > 0 {
return es[len(es)-1]
}
return nil
}
// GetType is the same as GetAllType but returns the deepest matching error.
func GetType(err error, v interface{}) error {
es := GetAllType(err, v)
if len(es) > 0 {
return es[len(es)-1]
}
return nil
}
// GetAll gets all the errors that might be wrapped in err with the
// given message. The order of the errors is such that the outermost
// matching error (the most recent wrap) is index zero, and so on.
func GetAll(err error, msg string) []error {
var result []error
Walk(err, func(err error) {
if err.Error() == msg {
result = append(result, err)
}
})
return result
}
// GetAllType gets all the errors that are the same type as v.
//
// The order of the return value is the same as described in GetAll.
func GetAllType(err error, v interface{}) []error {
var result []error
var search string
if v != nil {
search = reflect.TypeOf(v).String()
}
Walk(err, func(err error) {
var needle string
if err != nil {
needle = reflect.TypeOf(err).String()
}
if needle == search {
result = append(result, err)
}
})
return result
}
// Walk walks all the wrapped errors in err and calls the callback. If
// err isn't a wrapped error, this will be called once for err. If err
// is a wrapped error, the callback will be called for both the wrapper
// that implements error as well as the wrapped error itself.
func Walk(err error, cb WalkFunc) {
if err == nil {
return
}
switch e := err.(type) {
case *wrappedError:
cb(e.Outer)
Walk(e.Inner, cb)
case Wrapper:
cb(err)
for _, err := range e.WrappedErrors() {
Walk(err, cb)
}
default:
cb(err)
}
}
// wrappedError is an implementation of error that has both the
// outer and inner errors.
type wrappedError struct {
Outer error
Inner error
}
func (w *wrappedError) Error() string {
return w.Outer.Error()
}
func (w *wrappedError) WrappedErrors() []error {
return []error{w.Outer, w.Inner}
}

1
vendor/github.com/hashicorp/errwrap/go.mod generated vendored Normal file
View file

@ -0,0 +1 @@
module github.com/hashicorp/errwrap

View file

@ -1,5 +1,11 @@
# go-multierror
[![Build Status](http://img.shields.io/travis/hashicorp/go-multierror.svg?style=flat-square)][travis]
[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs]
[travis]: https://travis-ci.org/hashicorp/go-multierror
[godocs]: https://godoc.org/github.com/hashicorp/go-multierror
`go-multierror` is a package for Go that provides a mechanism for
representing a list of `error` values as a single `error`.

View file

@ -14,7 +14,20 @@ func Append(err error, errs ...error) *Error {
err = new(Error)
}
err.Errors = append(err.Errors, errs...)
// Go through each error and flatten
for _, e := range errs {
switch e := e.(type) {
case *Error:
if e != nil {
err.Errors = append(err.Errors, e.Errors...)
}
default:
if e != nil {
err.Errors = append(err.Errors, e)
}
}
}
return err
default:
newErrs := make([]error, 0, len(errs)+1)
@ -23,8 +36,6 @@ func Append(err error, errs ...error) *Error {
}
newErrs = append(newErrs, errs...)
return &Error{
Errors: newErrs,
}
return Append(&Error{}, newErrs...)
}
}

26
vendor/github.com/hashicorp/go-multierror/flatten.go generated vendored Normal file
View file

@ -0,0 +1,26 @@
package multierror
// Flatten flattens the given error, merging any *Errors together into
// a single *Error.
func Flatten(err error) error {
// If it isn't an *Error, just return the error as-is
if _, ok := err.(*Error); !ok {
return err
}
// Otherwise, make the result and flatten away!
flatErr := new(Error)
flatten(err, flatErr)
return flatErr
}
func flatten(err error, flatErr *Error) {
switch err := err.(type) {
case *Error:
for _, e := range err.Errors {
flatten(e, flatErr)
}
default:
flatErr.Errors = append(flatErr.Errors, err)
}
}

View file

@ -12,12 +12,16 @@ type ErrorFormatFunc func([]error) string
// ListFormatFunc is a basic formatter that outputs the number of errors
// that occurred along with a bullet point list of the errors.
func ListFormatFunc(es []error) string {
if len(es) == 1 {
return fmt.Sprintf("1 error occurred:\n\t* %s\n\n", es[0])
}
points := make([]string, len(es))
for i, err := range es {
points[i] = fmt.Sprintf("* %s", err)
}
return fmt.Sprintf(
"%d error(s) occurred:\n\n%s",
len(es), strings.Join(points, "\n"))
"%d errors occurred:\n\t%s\n\n",
len(es), strings.Join(points, "\n\t"))
}

3
vendor/github.com/hashicorp/go-multierror/go.mod generated vendored Normal file
View file

@ -0,0 +1,3 @@
module github.com/hashicorp/go-multierror
require github.com/hashicorp/errwrap v1.0.0

View file

@ -40,11 +40,11 @@ func (e *Error) GoString() string {
}
// WrappedErrors returns the list of errors that this Error is wrapping.
// It is an implementatin of the errwrap.Wrapper interface so that
// It is an implementation of the errwrap.Wrapper interface so that
// multierror.Error can be used with that library.
//
// This method is not safe to be called concurrently and is no different
// than accessing the Errors field directly. It is implementd only to
// than accessing the Errors field directly. It is implemented only to
// satisfy the errwrap.Wrapper interface.
func (e *Error) WrappedErrors() []error {
return e.Errors

37
vendor/github.com/hashicorp/go-multierror/prefix.go generated vendored Normal file
View file

@ -0,0 +1,37 @@
package multierror
import (
"fmt"
"github.com/hashicorp/errwrap"
)
// Prefix is a helper function that will prefix some text
// to the given error. If the error is a multierror.Error, then
// it will be prefixed to each wrapped error.
//
// This is useful to use when appending multiple multierrors
// together in order to give better scoping.
func Prefix(err error, prefix string) error {
if err == nil {
return nil
}
format := fmt.Sprintf("%s {{err}}", prefix)
switch err := err.(type) {
case *Error:
// Typed nils can reach here, so initialize if we are nil
if err == nil {
err = new(Error)
}
// Wrap each of the errors
for i, e := range err.Errors {
err.Errors[i] = errwrap.Wrapf(format, e)
}
return err
default:
return errwrap.Wrapf(format, err)
}
}

16
vendor/github.com/hashicorp/go-multierror/sort.go generated vendored Normal file
View file

@ -0,0 +1,16 @@
package multierror
// Len implements sort.Interface function for length
func (err Error) Len() int {
return len(err.Errors)
}
// Swap implements sort.Interface function for swapping elements
func (err Error) Swap(i, j int) {
err.Errors[i], err.Errors[j] = err.Errors[j], err.Errors[i]
}
// Less implements sort.Interface function for determining order
func (err Error) Less(i, j int) bool {
return err.Errors[i].Error() < err.Errors[j].Error()
}

8
vendor/github.com/hashicorp/go-sockaddr/go.mod generated vendored Normal file
View file

@ -0,0 +1,8 @@
module github.com/hashicorp/go-sockaddr
require (
github.com/hashicorp/errwrap v1.0.0
github.com/mitchellh/cli v1.0.0
github.com/mitchellh/go-wordwrap v1.0.0
github.com/ryanuber/columnize v2.1.0+incompatible
)

View file

@ -1197,18 +1197,12 @@ func parseDefaultIfNameFromRoute(routeOut string) (string, error) {
// parseDefaultIfNameFromIPCmd parses the default interface from ip(8) for
// Linux.
func parseDefaultIfNameFromIPCmd(routeOut string) (string, error) {
lines := strings.Split(routeOut, "\n")
re := whitespaceRE.Copy()
for _, line := range lines {
kvs := re.Split(line, -1)
if len(kvs) < 5 {
continue
}
if kvs[0] == "default" &&
kvs[1] == "via" &&
kvs[3] == "dev" {
ifName := strings.TrimSpace(kvs[4])
parsedLines := parseIfNameFromIPCmd(routeOut)
for _, parsedLine := range parsedLines {
if parsedLine[0] == "default" &&
parsedLine[1] == "via" &&
parsedLine[3] == "dev" {
ifName := strings.TrimSpace(parsedLine[4])
return ifName, nil
}
}
@ -1216,6 +1210,35 @@ func parseDefaultIfNameFromIPCmd(routeOut string) (string, error) {
return "", errors.New("No default interface found")
}
// parseDefaultIfNameFromIPCmdAndroid parses the default interface from ip(8) for
// Android.
func parseDefaultIfNameFromIPCmdAndroid(routeOut string) (string, error) {
parsedLines := parseIfNameFromIPCmd(routeOut)
if (len(parsedLines) > 0) {
ifName := strings.TrimSpace(parsedLines[0][4])
return ifName, nil
}
return "", errors.New("No default interface found")
}
// parseIfNameFromIPCmd parses interfaces from ip(8) for
// Linux.
func parseIfNameFromIPCmd(routeOut string) [][]string {
lines := strings.Split(routeOut, "\n")
re := whitespaceRE.Copy()
parsedLines := make([][]string, 0, len(lines))
for _, line := range lines {
kvs := re.Split(line, -1)
if len(kvs) < 5 {
continue
}
parsedLines = append(parsedLines, kvs)
}
return parsedLines
}
// parseDefaultIfNameWindows parses the default interface from `netstat -rn` and
// `ipconfig` on Windows.
func parseDefaultIfNameWindows(routeOut, ipconfigOut string) (string, error) {

View file

@ -0,0 +1,34 @@
package sockaddr
import (
"errors"
"os/exec"
)
type routeInfo struct {
cmds map[string][]string
}
// NewRouteInfo returns a Android-specific implementation of the RouteInfo
// interface.
func NewRouteInfo() (routeInfo, error) {
return routeInfo{
cmds: map[string][]string{"ip": {"/system/bin/ip", "route", "get", "8.8.8.8"}},
}, nil
}
// GetDefaultInterfaceName returns the interface name attached to the default
// route on the default interface.
func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
out, err := exec.Command(ri.cmds["ip"][0], ri.cmds["ip"][1:]...).Output()
if err != nil {
return "", err
}
var ifName string
if ifName, err = parseDefaultIfNameFromIPCmdAndroid(string(out)); err != nil {
return "", errors.New("No default interface found")
}
return ifName, nil
}

View file

@ -1,3 +1,5 @@
// +build !android
package sockaddr
import (

27
vendor/github.com/ishidawataru/sctp/GO_LICENSE generated vendored Normal file
View file

@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

218
vendor/github.com/ishidawataru/sctp/ipsock_linux.go generated vendored Normal file
View file

@ -0,0 +1,218 @@
package sctp
import (
"net"
"os"
"sync"
"syscall"
)
//from https://github.com/golang/go
// Boolean to int.
func boolint(b bool) int {
if b {
return 1
}
return 0
}
//from https://github.com/golang/go
func ipToSockaddr(family int, ip net.IP, port int, zone string) (syscall.Sockaddr, error) {
switch family {
case syscall.AF_INET:
if len(ip) == 0 {
ip = net.IPv4zero
}
ip4 := ip.To4()
if ip4 == nil {
return nil, &net.AddrError{Err: "non-IPv4 address", Addr: ip.String()}
}
sa := &syscall.SockaddrInet4{Port: port}
copy(sa.Addr[:], ip4)
return sa, nil
case syscall.AF_INET6:
// In general, an IP wildcard address, which is either
// "0.0.0.0" or "::", means the entire IP addressing
// space. For some historical reason, it is used to
// specify "any available address" on some operations
// of IP node.
//
// When the IP node supports IPv4-mapped IPv6 address,
// we allow an listener to listen to the wildcard
// address of both IP addressing spaces by specifying
// IPv6 wildcard address.
if len(ip) == 0 || ip.Equal(net.IPv4zero) {
ip = net.IPv6zero
}
// We accept any IPv6 address including IPv4-mapped
// IPv6 address.
ip6 := ip.To16()
if ip6 == nil {
return nil, &net.AddrError{Err: "non-IPv6 address", Addr: ip.String()}
}
//we set ZoneId to 0, as currently we use this functon only to probe the IP capabilities of the host
//if real Zone handling is required, the zone cache implementation in golang/net should be pulled here
sa := &syscall.SockaddrInet6{Port: port, ZoneId: 0}
copy(sa.Addr[:], ip6)
return sa, nil
}
return nil, &net.AddrError{Err: "invalid address family", Addr: ip.String()}
}
//from https://github.com/golang/go
func sockaddr(a *net.TCPAddr, family int) (syscall.Sockaddr, error) {
if a == nil {
return nil, nil
}
return ipToSockaddr(family, a.IP, a.Port, a.Zone)
}
//from https://github.com/golang/go
type ipStackCapabilities struct {
sync.Once // guards following
ipv4Enabled bool
ipv6Enabled bool
ipv4MappedIPv6Enabled bool
}
//from https://github.com/golang/go
var ipStackCaps ipStackCapabilities
//from https://github.com/golang/go
// supportsIPv4 reports whether the platform supports IPv4 networking
// functionality.
func supportsIPv4() bool {
ipStackCaps.Once.Do(ipStackCaps.probe)
return ipStackCaps.ipv4Enabled
}
//from https://github.com/golang/go
// supportsIPv6 reports whether the platform supports IPv6 networking
// functionality.
func supportsIPv6() bool {
ipStackCaps.Once.Do(ipStackCaps.probe)
return ipStackCaps.ipv6Enabled
}
//from https://github.com/golang/go
// supportsIPv4map reports whether the platform supports mapping an
// IPv4 address inside an IPv6 address at transport layer
// protocols. See RFC 4291, RFC 4038 and RFC 3493.
func supportsIPv4map() bool {
ipStackCaps.Once.Do(ipStackCaps.probe)
return ipStackCaps.ipv4MappedIPv6Enabled
}
//from https://github.com/golang/go
// Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication
// capabilities which are controlled by the IPV6_V6ONLY socket option
// and kernel configuration.
//
// Should we try to use the IPv4 socket interface if we're only
// dealing with IPv4 sockets? As long as the host system understands
// IPv4-mapped IPv6, it's okay to pass IPv4-mapeed IPv6 addresses to
// the IPv6 interface. That simplifies our code and is most
// general. Unfortunately, we need to run on kernels built without
// IPv6 support too. So probe the kernel to figure it out.
func (p *ipStackCapabilities) probe() {
s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
switch err {
case syscall.EAFNOSUPPORT, syscall.EPROTONOSUPPORT:
case nil:
syscall.Close(s)
p.ipv4Enabled = true
}
var probes = []struct {
laddr net.TCPAddr
value int
}{
// IPv6 communication capability
{laddr: net.TCPAddr{IP: net.IPv6loopback}, value: 1},
// IPv4-mapped IPv6 address communication capability
{laddr: net.TCPAddr{IP: net.IPv4(127, 0, 0, 1)}, value: 0},
}
for i := range probes {
s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
if err != nil {
continue
}
defer syscall.Close(s)
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value)
sa, err := sockaddr(&(probes[i].laddr), syscall.AF_INET6)
if err != nil {
continue
}
if err := syscall.Bind(s, sa); err != nil {
continue
}
if i == 0 {
p.ipv6Enabled = true
} else {
p.ipv4MappedIPv6Enabled = true
}
}
}
//from https://github.com/golang/go
//Change: we check the first IP address in the list of candidate SCTP IP addresses
func (a *SCTPAddr) isWildcard() bool {
if a == nil {
return true
}
if 0 == len(a.IPAddrs) {
return true
}
return a.IPAddrs[0].IP.IsUnspecified()
}
func (a *SCTPAddr) family() int {
if a != nil {
for _, ip := range a.IPAddrs {
if ip.IP.To4() == nil {
return syscall.AF_INET6
}
}
}
return syscall.AF_INET
}
//from https://github.com/golang/go
func favoriteAddrFamily(network string, laddr *SCTPAddr, raddr *SCTPAddr, mode string) (family int, ipv6only bool) {
switch network[len(network)-1] {
case '4':
return syscall.AF_INET, false
case '6':
return syscall.AF_INET6, true
}
if mode == "listen" && (laddr == nil || laddr.isWildcard()) {
if supportsIPv4map() || !supportsIPv4() {
return syscall.AF_INET6, false
}
if laddr == nil {
return syscall.AF_INET, false
}
return laddr.family(), false
}
if (laddr == nil || laddr.family() == syscall.AF_INET) &&
(raddr == nil || raddr.family() == syscall.AF_INET) {
return syscall.AF_INET, false
}
return syscall.AF_INET6, false
}
//from https://github.com/golang/go
//Changes: it is for SCTP only
func setDefaultSockopts(s int, family int, ipv6only bool) error {
if family == syscall.AF_INET6 {
// Allow both IP versions even if the OS default
// is otherwise. Note that some operating systems
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
// Allow broadcast.
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
}

View file

@ -197,37 +197,58 @@ func htons(h uint16) uint16 {
var ntohs = htons
func setNumOstreams(fd, num int) error {
param := InitMsg{
NumOstreams: uint16(num),
}
optlen := unsafe.Sizeof(param)
_, _, err := setsockopt(fd, SCTP_INITMSG, uintptr(unsafe.Pointer(&param)), uintptr(optlen))
// setInitOpts sets options for an SCTP association initialization
// see https://tools.ietf.org/html/rfc4960#page-25
func setInitOpts(fd int, options InitMsg) error {
optlen := unsafe.Sizeof(options)
_, _, err := setsockopt(fd, SCTP_INITMSG, uintptr(unsafe.Pointer(&options)), uintptr(optlen))
return err
}
func setNumOstreams(fd, num int) error {
return setInitOpts(fd, InitMsg{NumOstreams: uint16(num)})
}
type SCTPAddr struct {
IP []net.IP
Port int
IPAddrs []net.IPAddr
Port int
}
func (a *SCTPAddr) ToRawSockAddrBuf() []byte {
buf := []byte{}
p := htons(uint16(a.Port))
for _, ip := range a.IP {
if ip.To4() != nil {
if len(a.IPAddrs) == 0 { // if a.IPAddrs list is empty - fall back to IPv4 zero addr
s := syscall.RawSockaddrInet4{
Family: syscall.AF_INET,
Port: p,
}
copy(s.Addr[:], net.IPv4zero)
return toBuf(s)
}
buf := []byte{}
for _, ip := range a.IPAddrs {
ipBytes := ip.IP
if len(ipBytes) == 0 {
ipBytes = net.IPv4zero
}
if ip4 := ipBytes.To4(); ip4 != nil {
s := syscall.RawSockaddrInet4{
Family: syscall.AF_INET,
Port: p,
}
copy(s.Addr[:], ip.To4())
copy(s.Addr[:], ip4)
buf = append(buf, toBuf(s)...)
} else {
s := syscall.RawSockaddrInet6{
Family: syscall.AF_INET6,
Port: p,
var scopeid uint32
ifi, err := net.InterfaceByName(ip.Zone)
if err == nil {
scopeid = uint32(ifi.Index)
}
copy(s.Addr[:], ip)
s := syscall.RawSockaddrInet6{
Family: syscall.AF_INET6,
Port: p,
Scope_id: scopeid,
}
copy(s.Addr[:], ipBytes)
buf = append(buf, toBuf(s)...)
}
}
@ -237,15 +258,15 @@ func (a *SCTPAddr) ToRawSockAddrBuf() []byte {
func (a *SCTPAddr) String() string {
var b bytes.Buffer
for n, i := range a.IP {
if a.IP[n].To4() != nil {
for n, i := range a.IPAddrs {
if i.IP.To4() != nil {
b.WriteString(i.String())
} else if a.IP[n].To16() != nil {
} else if i.IP.To16() != nil {
b.WriteRune('[')
b.WriteString(i.String())
b.WriteRune(']')
}
if n < len(a.IP)-1 {
if n < len(a.IPAddrs)-1 {
b.WriteRune('/')
}
}
@ -260,6 +281,7 @@ func ResolveSCTPAddr(network, addrs string) (*SCTPAddr, error) {
tcpnet := ""
switch network {
case "", "sctp":
tcpnet = "tcp"
case "sctp4":
tcpnet = "tcp4"
case "sctp6":
@ -271,26 +293,26 @@ func ResolveSCTPAddr(network, addrs string) (*SCTPAddr, error) {
if len(elems) == 0 {
return nil, fmt.Errorf("invalid input: %s", addrs)
}
ipaddrs := make([]net.IP, 0, len(elems))
ipaddrs := make([]net.IPAddr, 0, len(elems))
for _, e := range elems[:len(elems)-1] {
tcpa, err := net.ResolveTCPAddr(tcpnet, e+":")
if err != nil {
return nil, err
}
ipaddrs = append(ipaddrs, tcpa.IP)
ipaddrs = append(ipaddrs, net.IPAddr{IP: tcpa.IP, Zone: tcpa.Zone})
}
tcpa, err := net.ResolveTCPAddr(tcpnet, elems[len(elems)-1])
if err != nil {
return nil, err
}
if tcpa.IP != nil {
ipaddrs = append(ipaddrs, tcpa.IP)
ipaddrs = append(ipaddrs, net.IPAddr{IP: tcpa.IP, Zone: tcpa.Zone})
} else {
ipaddrs = nil
}
return &SCTPAddr{
IP: ipaddrs,
Port: tcpa.Port,
IPAddrs: ipaddrs,
Port: tcpa.Port,
}, nil
}
@ -357,15 +379,12 @@ func (c *SCTPConn) Read(b []byte) (int, error) {
}
func (c *SCTPConn) SetInitMsg(numOstreams, maxInstreams, maxAttempts, maxInitTimeout int) error {
param := InitMsg{
return setInitOpts(c.fd(), InitMsg{
NumOstreams: uint16(numOstreams),
MaxInstreams: uint16(maxInstreams),
MaxAttempts: uint16(maxAttempts),
MaxInitTimeout: uint16(maxInitTimeout),
}
optlen := unsafe.Sizeof(param)
_, _, err := setsockopt(c.fd(), SCTP_INITMSG, uintptr(unsafe.Pointer(&param)), uintptr(optlen))
return err
})
}
func (c *SCTPConn) SubscribeEvents(flags int) error {
@ -473,7 +492,7 @@ func (c *SCTPConn) GetDefaultSentParam() (*SndRcvInfo, error) {
func resolveFromRawAddr(ptr unsafe.Pointer, n int) (*SCTPAddr, error) {
addr := &SCTPAddr{
IP: make([]net.IP, n),
IPAddrs: make([]net.IPAddr, n),
}
switch family := (*(*syscall.RawSockaddrAny)(ptr)).Addr.Family; family {
@ -484,7 +503,7 @@ func resolveFromRawAddr(ptr unsafe.Pointer, n int) (*SCTPAddr, error) {
for i := 0; i < n; i++ {
a := *(*syscall.RawSockaddrInet4)(unsafe.Pointer(
uintptr(ptr) + size*uintptr(i)))
addr.IP[i] = a.Addr[:]
addr.IPAddrs[i] = net.IPAddr{IP: a.Addr[:]}
}
case syscall.AF_INET6:
addr.Port = int(ntohs(uint16((*(*syscall.RawSockaddrInet4)(ptr)).Port)))
@ -493,7 +512,12 @@ func resolveFromRawAddr(ptr unsafe.Pointer, n int) (*SCTPAddr, error) {
for i := 0; i < n; i++ {
a := *(*syscall.RawSockaddrInet6)(unsafe.Pointer(
uintptr(ptr) + size*uintptr(i)))
addr.IP[i] = a.Addr[:]
var zone string
ifi, err := net.InterfaceByIndex(int(a.Scope_id))
if err == nil {
zone = ifi.Name
}
addr.IPAddrs[i] = net.IPAddr{IP: a.Addr[:], Zone: zone}
}
default:
return nil, fmt.Errorf("unknown address family: %d", family)

View file

@ -3,7 +3,6 @@
package sctp
import (
"fmt"
"io"
"net"
"sync/atomic"
@ -115,31 +114,14 @@ func (c *SCTPConn) Close() error {
return syscall.EBADF
}
// ListenSCTP - start listener on specified address/port
func ListenSCTP(net string, laddr *SCTPAddr) (*SCTPListener, error) {
af := syscall.AF_INET
switch net {
case "sctp":
hasv6 := func(addr *SCTPAddr) bool {
if addr == nil {
return false
}
for _, ip := range addr.IP {
if ip.To4() == nil {
return true
}
}
return false
}
if hasv6(laddr) {
af = syscall.AF_INET6
}
case "sctp4":
case "sctp6":
af = syscall.AF_INET6
default:
return nil, fmt.Errorf("invalid net: %s", net)
}
return ListenSCTPExt(net, laddr, InitMsg{NumOstreams: SCTP_MAX_STREAM})
}
// ListenSCTPExt - start listener on specified address/port with given SCTP options
func ListenSCTPExt(network string, laddr *SCTPAddr, options InitMsg) (*SCTPListener, error) {
af, ipv6only := favoriteAddrFamily(network, laddr, nil, "listen")
sock, err := syscall.Socket(
af,
syscall.SOCK_STREAM,
@ -148,11 +130,30 @@ func ListenSCTP(net string, laddr *SCTPAddr) (*SCTPListener, error) {
if err != nil {
return nil, err
}
err = setNumOstreams(sock, SCTP_MAX_STREAM)
// close socket on error
defer func() {
if err != nil {
syscall.Close(sock)
}
}()
if err = setDefaultSockopts(sock, af, ipv6only); err != nil {
return nil, err
}
err = setInitOpts(sock, options)
if err != nil {
return nil, err
}
if laddr != nil && len(laddr.IP) != 0 {
if laddr != nil {
// If IP address and/or port was not provided so far, let's use the unspecified IPv4 or IPv6 address
if len(laddr.IPAddrs) == 0 {
if af == syscall.AF_INET {
laddr.IPAddrs = append(laddr.IPAddrs, net.IPAddr{IP: net.IPv4zero})
} else if af == syscall.AF_INET6 {
laddr.IPAddrs = append(laddr.IPAddrs, net.IPAddr{IP: net.IPv6zero})
}
}
err := SCTPBind(sock, laddr, SCTP_BINDX_ADD_ADDR)
if err != nil {
return nil, err
@ -167,40 +168,30 @@ func ListenSCTP(net string, laddr *SCTPAddr) (*SCTPListener, error) {
}, nil
}
func (ln *SCTPListener) Accept() (net.Conn, error) {
// AcceptSCTP waits for and returns the next SCTP connection to the listener.
func (ln *SCTPListener) AcceptSCTP() (*SCTPConn, error) {
fd, _, err := syscall.Accept4(ln.fd, 0)
return NewSCTPConn(fd, nil), err
}
// Accept waits for and returns the next connection connection to the listener.
func (ln *SCTPListener) Accept() (net.Conn, error) {
return ln.AcceptSCTP()
}
func (ln *SCTPListener) Close() error {
syscall.Shutdown(ln.fd, syscall.SHUT_RDWR)
return syscall.Close(ln.fd)
}
// DialSCTP - bind socket to laddr (if given) and connect to raddr
func DialSCTP(net string, laddr, raddr *SCTPAddr) (*SCTPConn, error) {
af := syscall.AF_INET
switch net {
case "sctp":
hasv6 := func(addr *SCTPAddr) bool {
if addr == nil {
return false
}
for _, ip := range addr.IP {
if ip.To4() == nil {
return true
}
}
return false
}
if hasv6(laddr) || hasv6(raddr) {
af = syscall.AF_INET6
}
case "sctp4":
case "sctp6":
af = syscall.AF_INET6
default:
return nil, fmt.Errorf("invalid net: %s", net)
}
return DialSCTPExt(net, laddr, raddr, InitMsg{NumOstreams: SCTP_MAX_STREAM})
}
// DialSCTPExt - same as DialSCTP but with given SCTP options
func DialSCTPExt(network string, laddr, raddr *SCTPAddr, options InitMsg) (*SCTPConn, error) {
af, ipv6only := favoriteAddrFamily(network, laddr, raddr, "dial")
sock, err := syscall.Socket(
af,
syscall.SOCK_STREAM,
@ -209,11 +200,29 @@ func DialSCTP(net string, laddr, raddr *SCTPAddr) (*SCTPConn, error) {
if err != nil {
return nil, err
}
err = setNumOstreams(sock, SCTP_MAX_STREAM)
// close socket on error
defer func() {
if err != nil {
syscall.Close(sock)
}
}()
if err = setDefaultSockopts(sock, af, ipv6only); err != nil {
return nil, err
}
err = setInitOpts(sock, options)
if err != nil {
return nil, err
}
if laddr != nil {
// If IP address and/or port was not provided so far, let's use the unspecified IPv4 or IPv6 address
if len(laddr.IPAddrs) == 0 {
if af == syscall.AF_INET {
laddr.IPAddrs = append(laddr.IPAddrs, net.IPAddr{IP: net.IPv4zero})
} else if af == syscall.AF_INET6 {
laddr.IPAddrs = append(laddr.IPAddrs, net.IPAddr{IP: net.IPv6zero})
}
}
err := SCTPBind(sock, laddr, SCTP_BINDX_ADD_ADDR)
if err != nil {
return nil, err

View file

@ -34,10 +34,18 @@ func ListenSCTP(net string, laddr *SCTPAddr) (*SCTPListener, error) {
return nil, ErrUnsupported
}
func ListenSCTPExt(net string, laddr *SCTPAddr, options InitMsg) (*SCTPListener, error) {
return nil, ErrUnsupported
}
func (ln *SCTPListener) Accept() (net.Conn, error) {
return nil, ErrUnsupported
}
func (ln *SCTPListener) AcceptSCTP() (*SCTPConn, error) {
return nil, ErrUnsupported
}
func (ln *SCTPListener) Close() error {
return ErrUnsupported
}
@ -45,3 +53,7 @@ func (ln *SCTPListener) Close() error {
func DialSCTP(net string, laddr, raddr *SCTPAddr) (*SCTPConn, error) {
return nil, ErrUnsupported
}
func DialSCTPExt(network string, laddr, raddr *SCTPAddr, options InitMsg) (*SCTPConn, error) {
return nil, ErrUnsupported
}

View file

@ -89,3 +89,4 @@ There are also a few pieces of low level netlink functionality that still
need to be implemented. Routing rules are not in place and some of the
more advanced link types. Hopefully there is decent structure and testing
in place to make these fairly straightforward to add.

View file

@ -8,6 +8,7 @@ import (
"github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
)
// IFA_FLAGS is a u32 attribute.
@ -22,7 +23,7 @@ func AddrAdd(link Link, addr *Addr) error {
// AddrAdd will add an IP address to a link device.
// Equivalent to: `ip addr add $addr dev $link`
func (h *Handle) AddrAdd(link Link, addr *Addr) error {
req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
return h.addrHandle(link, addr, req)
}
@ -35,7 +36,7 @@ func AddrReplace(link Link, addr *Addr) error {
// AddrReplace will replace (or, if not present, add) an IP address on a link device.
// Equivalent to: `ip addr replace $addr dev $link`
func (h *Handle) AddrReplace(link Link, addr *Addr) error {
req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE|syscall.NLM_F_ACK)
req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_REPLACE|unix.NLM_F_ACK)
return h.addrHandle(link, addr, req)
}
@ -48,7 +49,7 @@ func AddrDel(link Link, addr *Addr) error {
// AddrDel will delete an IP address from a link device.
// Equivalent to: `ip addr del $addr dev $link`
func (h *Handle) AddrDel(link Link, addr *Addr) error {
req := h.newNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK)
req := h.newNetlinkRequest(unix.RTM_DELADDR, unix.NLM_F_ACK)
return h.addrHandle(link, addr, req)
}
@ -75,7 +76,7 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
localAddrData = addr.IP.To16()
}
localData := nl.NewRtAttr(syscall.IFA_LOCAL, localAddrData)
localData := nl.NewRtAttr(unix.IFA_LOCAL, localAddrData)
req.AddData(localData)
var peerAddrData []byte
if addr.Peer != nil {
@ -88,7 +89,7 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
peerAddrData = localAddrData
}
addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, peerAddrData)
addressData := nl.NewRtAttr(unix.IFA_ADDRESS, peerAddrData)
req.AddData(addressData)
if addr.Flags != 0 {
@ -102,21 +103,34 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
}
}
if addr.Broadcast == nil {
calcBroadcast := make(net.IP, masklen/8)
for i := range localAddrData {
calcBroadcast[i] = localAddrData[i] | ^addr.Mask[i]
if family == FAMILY_V4 {
if addr.Broadcast == nil {
calcBroadcast := make(net.IP, masklen/8)
for i := range localAddrData {
calcBroadcast[i] = localAddrData[i] | ^addr.Mask[i]
}
addr.Broadcast = calcBroadcast
}
addr.Broadcast = calcBroadcast
}
req.AddData(nl.NewRtAttr(syscall.IFA_BROADCAST, addr.Broadcast))
req.AddData(nl.NewRtAttr(unix.IFA_BROADCAST, addr.Broadcast))
if addr.Label != "" {
labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label))
req.AddData(labelData)
if addr.Label != "" {
labelData := nl.NewRtAttr(unix.IFA_LABEL, nl.ZeroTerminated(addr.Label))
req.AddData(labelData)
}
}
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
// 0 is the default value for these attributes. However, 0 means "expired", while the least-surprising default
// value should be "forever". To compensate for that, only add the attributes if at least one of the values is
// non-zero, which means the caller has explicitly set them
if addr.ValidLft > 0 || addr.PreferedLft > 0 {
cachedata := nl.IfaCacheInfo{
IfaValid: uint32(addr.ValidLft),
IfaPrefered: uint32(addr.PreferedLft),
}
req.AddData(nl.NewRtAttr(unix.IFA_CACHEINFO, cachedata.Serialize()))
}
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
@ -131,11 +145,11 @@ func AddrList(link Link, family int) ([]Addr, error) {
// Equivalent to: `ip addr show`.
// The list can be filtered by link and ip family.
func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
req := h.newNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
req := h.newNetlinkRequest(unix.RTM_GETADDR, unix.NLM_F_DUMP)
msg := nl.NewIfInfomsg(family)
req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR)
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
if err != nil {
return nil, err
}
@ -187,21 +201,21 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
var local, dst *net.IPNet
for _, attr := range attrs {
switch attr.Attr.Type {
case syscall.IFA_ADDRESS:
case unix.IFA_ADDRESS:
dst = &net.IPNet{
IP: attr.Value,
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
}
addr.Peer = dst
case syscall.IFA_LOCAL:
case unix.IFA_LOCAL:
local = &net.IPNet{
IP: attr.Value,
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
}
addr.IPNet = local
case syscall.IFA_BROADCAST:
case unix.IFA_BROADCAST:
addr.Broadcast = attr.Value
case syscall.IFA_LABEL:
case unix.IFA_LABEL:
addr.Label = string(attr.Value[:len(attr.Value)-1])
case IFA_FLAGS:
addr.Flags = int(native.Uint32(attr.Value[0:4]))
@ -236,13 +250,13 @@ 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)
return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
}
// 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)
return addrSubscribeAt(ns, netns.None(), ch, done, nil, false)
}
// AddrSubscribeOptions contains a set of options to use with
@ -250,6 +264,7 @@ func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct
type AddrSubscribeOptions struct {
Namespace *netns.NsHandle
ErrorCallback func(error)
ListExisting bool
}
// AddrSubscribeWithOptions work like AddrSubscribe but enable to
@ -260,11 +275,11 @@ 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)
return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
}
func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error)) error {
s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR)
func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_IFADDR, unix.RTNLGRP_IPV6_IFADDR)
if err != nil {
return err
}
@ -274,6 +289,15 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
s.Close()
}()
}
if listExisting {
req := pkgHandle.newNetlinkRequest(unix.RTM_GETADDR,
unix.NLM_F_DUMP)
infmsg := nl.NewIfInfomsg(unix.AF_UNSPEC)
req.AddData(infmsg)
if err := s.Send(req); err != nil {
return err
}
}
go func() {
defer close(ch)
for {
@ -285,8 +309,22 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
return
}
for _, m := range msgs {
if m.Header.Type == unix.NLMSG_DONE {
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
}
msgType := m.Header.Type
if msgType != syscall.RTM_NEWADDR && msgType != syscall.RTM_DELADDR {
if msgType != unix.RTM_NEWADDR && msgType != unix.RTM_DELADDR {
if cberr != nil {
cberr(fmt.Errorf("bad message type: %d", msgType))
}
@ -303,7 +341,7 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
ch <- AddrUpdate{LinkAddress: *addr.IPNet,
LinkIndex: ifindex,
NewAddr: msgType == syscall.RTM_NEWADDR,
NewAddr: msgType == unix.RTM_NEWADDR,
Flags: addr.Flags,
Scope: addr.Scope,
PreferedLft: addr.PreferedLft,

View file

@ -1,49 +1,12 @@
package netlink
/*
#include <asm/types.h>
#include <asm/unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
import (
"unsafe"
static int load_simple_bpf(int prog_type, int ret) {
#ifdef __NR_bpf
// { return ret; }
__u64 __attribute__((aligned(8))) insns[] = {
0x00000000000000b7ull | ((__u64)ret<<32),
0x0000000000000095ull,
};
__u8 __attribute__((aligned(8))) license[] = "ASL2";
// Copied from a header file since libc is notoriously slow to update.
// The call will succeed or fail and that will be our indication on
// whether or not it is supported.
struct {
__u32 prog_type;
__u32 insn_cnt;
__u64 insns;
__u64 license;
__u32 log_level;
__u32 log_size;
__u64 log_buf;
__u32 kern_version;
} __attribute__((aligned(8))) attr = {
.prog_type = prog_type,
.insn_cnt = 2,
.insns = (uintptr_t)&insns,
.license = (uintptr_t)&license,
};
return syscall(__NR_bpf, 5, &attr, sizeof(attr));
#else
errno = EINVAL;
return -1;
#endif
}
*/
import "C"
"golang.org/x/sys/unix"
)
type BpfProgType C.int
type BpfProgType uint32
const (
BPF_PROG_TYPE_UNSPEC BpfProgType = iota
@ -55,8 +18,36 @@ const (
BPF_PROG_TYPE_XDP
)
// loadSimpleBpf loads a trivial bpf program for testing purposes
func loadSimpleBpf(progType BpfProgType, ret int) (int, error) {
fd, err := C.load_simple_bpf(C.int(progType), C.int(ret))
return int(fd), err
type BPFAttr struct {
ProgType uint32
InsnCnt uint32
Insns uintptr
License uintptr
LogLevel uint32
LogSize uint32
LogBuf uintptr
KernVersion uint32
}
// loadSimpleBpf loads a trivial bpf program for testing purposes.
func loadSimpleBpf(progType BpfProgType, ret uint32) (int, error) {
insns := []uint64{
0x00000000000000b7 | (uint64(ret) << 32),
0x0000000000000095,
}
license := []byte{'A', 'S', 'L', '2', '\x00'}
attr := BPFAttr{
ProgType: uint32(progType),
InsnCnt: uint32(len(insns)),
Insns: uintptr(unsafe.Pointer(&insns[0])),
License: uintptr(unsafe.Pointer(&license[0])),
}
fd, _, errno := unix.Syscall(unix.SYS_BPF,
5, /* bpf cmd */
uintptr(unsafe.Pointer(&attr)),
unsafe.Sizeof(attr))
if errno != 0 {
return 0, errno
}
return int(fd), nil
}

View file

@ -2,9 +2,9 @@ package netlink
import (
"fmt"
"syscall"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
// BridgeVlanList gets a map of device id to bridge vlan infos.
@ -16,12 +16,12 @@ func BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
// BridgeVlanList gets a map of device id to bridge vlan infos.
// Equivalent to: `bridge vlan show`
func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP)
msg := nl.NewIfInfomsg(syscall.AF_BRIDGE)
req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
req.AddData(msg)
req.AddData(nl.NewRtAttr(nl.IFLA_EXT_MASK, nl.Uint32Attr(uint32(nl.RTEXT_FILTER_BRVLAN))))
req.AddData(nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(uint32(nl.RTEXT_FILTER_BRVLAN))))
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWLINK)
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
if err != nil {
return nil, err
}
@ -35,7 +35,7 @@ func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
}
for _, attr := range attrs {
switch attr.Attr.Type {
case nl.IFLA_AF_SPEC:
case unix.IFLA_AF_SPEC:
//nested attr
nestAttrs, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
@ -63,7 +63,7 @@ func BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) err
// BridgeVlanAdd adds a new vlan filter entry
// Equivalent to: `bridge vlan add dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
func (h *Handle) BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) error {
return h.bridgeVlanModify(syscall.RTM_SETLINK, link, vid, pvid, untagged, self, master)
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, pvid, untagged, self, master)
}
// BridgeVlanDel adds a new vlan filter entry
@ -75,19 +75,19 @@ func BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) err
// BridgeVlanDel adds a new vlan filter entry
// Equivalent to: `bridge vlan del dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
func (h *Handle) BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) error {
return h.bridgeVlanModify(syscall.RTM_DELLINK, link, vid, pvid, untagged, self, master)
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, pvid, untagged, self, master)
}
func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged, self, master bool) error {
base := link.Attrs()
h.ensureIndex(base)
req := h.newNetlinkRequest(cmd, syscall.NLM_F_ACK)
req := h.newNetlinkRequest(cmd, unix.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_BRIDGE)
msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
msg.Index = int32(base.Index)
req.AddData(msg)
br := nl.NewRtAttr(nl.IFLA_AF_SPEC, nil)
br := nl.NewRtAttr(unix.IFLA_AF_SPEC, nil)
var flags uint16
if self {
flags |= nl.BRIDGE_FLAGS_SELF
@ -107,7 +107,7 @@ func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged
}
nl.NewRtAttrChild(br, nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
req.AddData(br)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
if err != nil {
return err
}

View file

@ -5,6 +5,7 @@ import (
"syscall"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
// NOTE: function is in here because it uses other linux functions
@ -50,7 +51,7 @@ func ClassDel(class Class) error {
// ClassDel will delete a class from the system.
// Equivalent to: `tc class del $class`
func (h *Handle) ClassDel(class Class) error {
return h.classModify(syscall.RTM_DELTCLASS, 0, class)
return h.classModify(unix.RTM_DELTCLASS, 0, class)
}
// ClassChange will change a class in place
@ -64,7 +65,7 @@ func ClassChange(class Class) error {
// Equivalent to: `tc class change $class`
// The parent and handle MUST NOT be changed.
func (h *Handle) ClassChange(class Class) error {
return h.classModify(syscall.RTM_NEWTCLASS, 0, class)
return h.classModify(unix.RTM_NEWTCLASS, 0, class)
}
// ClassReplace will replace a class to the system.
@ -82,7 +83,7 @@ func ClassReplace(class Class) error {
// If a class already exist with this parent/handle pair, the class is changed.
// If a class does not already exist with this parent/handle, a new class is created.
func (h *Handle) ClassReplace(class Class) error {
return h.classModify(syscall.RTM_NEWTCLASS, syscall.NLM_F_CREATE, class)
return h.classModify(unix.RTM_NEWTCLASS, unix.NLM_F_CREATE, class)
}
// ClassAdd will add a class to the system.
@ -95,14 +96,14 @@ func ClassAdd(class Class) error {
// Equivalent to: `tc class add $class`
func (h *Handle) ClassAdd(class Class) error {
return h.classModify(
syscall.RTM_NEWTCLASS,
syscall.NLM_F_CREATE|syscall.NLM_F_EXCL,
unix.RTM_NEWTCLASS,
unix.NLM_F_CREATE|unix.NLM_F_EXCL,
class,
)
}
func (h *Handle) classModify(cmd, flags int, class Class) error {
req := h.newNetlinkRequest(cmd, flags|syscall.NLM_F_ACK)
req := h.newNetlinkRequest(cmd, flags|unix.NLM_F_ACK)
base := class.Attrs()
msg := &nl.TcMsg{
Family: nl.FAMILY_ALL,
@ -112,12 +113,12 @@ func (h *Handle) classModify(cmd, flags int, class Class) error {
}
req.AddData(msg)
if cmd != syscall.RTM_DELTCLASS {
if cmd != unix.RTM_DELTCLASS {
if err := classPayload(req, class); err != nil {
return err
}
}
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
@ -141,12 +142,12 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
var rtab [256]uint32
var ctab [256]uint32
tcrate := nl.TcRateSpec{Rate: uint32(htb.Rate)}
if CalcRtable(&tcrate, rtab, cellLog, uint32(mtu), linklayer) < 0 {
if CalcRtable(&tcrate, rtab[:], cellLog, uint32(mtu), linklayer) < 0 {
return errors.New("HTB: failed to calculate rate table")
}
opt.Rate = tcrate
tcceil := nl.TcRateSpec{Rate: uint32(htb.Ceil)}
if CalcRtable(&tcceil, ctab, ccellLog, uint32(mtu), linklayer) < 0 {
if CalcRtable(&tcceil, ctab[:], ccellLog, uint32(mtu), linklayer) < 0 {
return errors.New("HTB: failed to calculate ceil rate table")
}
opt.Ceil = tcceil
@ -169,7 +170,7 @@ func ClassList(link Link, parent uint32) ([]Class, error) {
// Equivalent to: `tc class show`.
// Generally returns nothing if link and parent are not specified.
func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
req := h.newNetlinkRequest(syscall.RTM_GETTCLASS, syscall.NLM_F_DUMP)
req := h.newNetlinkRequest(unix.RTM_GETTCLASS, unix.NLM_F_DUMP)
msg := &nl.TcMsg{
Family: nl.FAMILY_ALL,
Parent: parent,
@ -181,7 +182,7 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
}
req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWTCLASS)
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTCLASS)
if err != nil {
return nil, err
}

View file

@ -6,9 +6,9 @@ import (
"errors"
"fmt"
"net"
"syscall"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
// ConntrackTableType Conntrack table for the netlink operation
@ -85,8 +85,8 @@ func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily)
// conntrack -F [table] Flush table
// The flush operation applies to all the family types
func (h *Handle) ConntrackTableFlush(table ConntrackTableType) error {
req := h.newConntrackRequest(table, syscall.AF_INET, nl.IPCTNL_MSG_CT_DELETE, syscall.NLM_F_ACK)
_, err := req.Execute(syscall.NETLINK_NETFILTER, 0)
req := h.newConntrackRequest(table, unix.AF_INET, nl.IPCTNL_MSG_CT_DELETE, unix.NLM_F_ACK)
_, err := req.Execute(unix.NETLINK_NETFILTER, 0)
return err
}
@ -102,10 +102,10 @@ func (h *Handle) ConntrackDeleteFilter(table ConntrackTableType, family InetFami
for _, dataRaw := range res {
flow := parseRawData(dataRaw)
if match := filter.MatchConntrackFlow(flow); match {
req2 := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_DELETE, syscall.NLM_F_ACK)
req2 := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_DELETE, unix.NLM_F_ACK)
// skip the first 4 byte that are the netfilter header, the newConntrackRequest is adding it already
req2.AddRawData(dataRaw[4:])
req2.Execute(syscall.NETLINK_NETFILTER, 0)
req2.Execute(unix.NETLINK_NETFILTER, 0)
matched++
}
}
@ -127,8 +127,8 @@ func (h *Handle) newConntrackRequest(table ConntrackTableType, family InetFamily
}
func (h *Handle) dumpConntrackTable(table ConntrackTableType, family InetFamily) ([][]byte, error) {
req := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_GET, syscall.NLM_F_DUMP)
return req.Execute(syscall.NETLINK_NETFILTER, 0)
req := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_GET, unix.NLM_F_DUMP)
return req.Execute(unix.NETLINK_NETFILTER, 0)
}
// The full conntrack flow structure is very complicated and can be found in the file:

View file

@ -17,7 +17,7 @@ type FilterAttrs struct {
Handle uint32
Parent uint32
Priority uint16 // lower is higher priority
Protocol uint16 // syscall.ETH_P_*
Protocol uint16 // unix.ETH_P_*
}
func (q FilterAttrs) String() string {
@ -225,6 +225,21 @@ func (filter *U32) Type() string {
return "u32"
}
// MatchAll filters match all packets
type MatchAll struct {
FilterAttrs
ClassId uint32
Actions []Action
}
func (filter *MatchAll) Attrs() *FilterAttrs {
return &filter.FilterAttrs
}
func (filter *MatchAll) Type() string {
return "matchall"
}
type FilterFwAttrs struct {
ClassId uint32
InDev string

View file

@ -9,6 +9,7 @@ import (
"unsafe"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
// Constants used in TcU32Sel.Flags.
@ -55,7 +56,7 @@ func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) {
if police.Rate.Rate != 0 {
police.Rate.Mpu = fattrs.Mpu
police.Rate.Overhead = fattrs.Overhead
if CalcRtable(&police.Rate, rtab, rcellLog, fattrs.Mtu, linklayer) < 0 {
if CalcRtable(&police.Rate, rtab[:], rcellLog, fattrs.Mtu, linklayer) < 0 {
return nil, errors.New("TBF: failed to calculate rate table")
}
police.Burst = uint32(Xmittime(uint64(police.Rate.Rate), uint32(buffer)))
@ -64,7 +65,7 @@ func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) {
if police.PeakRate.Rate != 0 {
police.PeakRate.Mpu = fattrs.Mpu
police.PeakRate.Overhead = fattrs.Overhead
if CalcRtable(&police.PeakRate, ptab, pcellLog, fattrs.Mtu, linklayer) < 0 {
if CalcRtable(&police.PeakRate, ptab[:], pcellLog, fattrs.Mtu, linklayer) < 0 {
return nil, errors.New("POLICE: failed to calculate peak rate table")
}
}
@ -98,7 +99,7 @@ func FilterDel(filter Filter) error {
// FilterDel will delete a filter from the system.
// Equivalent to: `tc filter del $filter`
func (h *Handle) FilterDel(filter Filter) error {
req := h.newNetlinkRequest(syscall.RTM_DELTFILTER, syscall.NLM_F_ACK)
req := h.newNetlinkRequest(unix.RTM_DELTFILTER, unix.NLM_F_ACK)
base := filter.Attrs()
msg := &nl.TcMsg{
Family: nl.FAMILY_ALL,
@ -109,7 +110,7 @@ func (h *Handle) FilterDel(filter Filter) error {
}
req.AddData(msg)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
@ -123,7 +124,7 @@ func FilterAdd(filter Filter) error {
// Equivalent to: `tc filter add $filter`
func (h *Handle) FilterAdd(filter Filter) error {
native = nl.NativeEndian()
req := h.newNetlinkRequest(syscall.RTM_NEWTFILTER, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
req := h.newNetlinkRequest(unix.RTM_NEWTFILTER, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
base := filter.Attrs()
msg := &nl.TcMsg{
Family: nl.FAMILY_ALL,
@ -221,10 +222,18 @@ func (h *Handle) FilterAdd(filter Filter) error {
bpfFlags |= nl.TCA_BPF_FLAG_ACT_DIRECT
}
nl.NewRtAttrChild(options, nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags))
case *MatchAll:
actionsAttr := nl.NewRtAttrChild(options, 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))
}
}
req.AddData(options)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
@ -239,7 +248,7 @@ func FilterList(link Link, parent uint32) ([]Filter, error) {
// Equivalent to: `tc filter show`.
// Generally returns nothing if link and parent are not specified.
func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
req := h.newNetlinkRequest(syscall.RTM_GETTFILTER, syscall.NLM_F_DUMP)
req := h.newNetlinkRequest(unix.RTM_GETTFILTER, unix.NLM_F_DUMP)
msg := &nl.TcMsg{
Family: nl.FAMILY_ALL,
Parent: parent,
@ -251,7 +260,7 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
}
req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWTFILTER)
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTFILTER)
if err != nil {
return nil, err
}
@ -287,6 +296,8 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
filter = &Fw{}
case "bpf":
filter = &BpfFilter{}
case "matchall":
filter = &MatchAll{}
default:
filter = &GenericFilter{FilterType: filterType}
}
@ -311,6 +322,11 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
if err != nil {
return nil, err
}
case "matchall":
detailed, err = parseMatchAllData(filter, data)
if err != nil {
return nil, err
}
default:
detailed = true
}
@ -540,6 +556,28 @@ func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
return detailed, nil
}
func parseMatchAllData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
native = nl.NativeEndian()
matchall := filter.(*MatchAll)
detailed := true
for _, datum := range data {
switch datum.Attr.Type {
case nl.TCA_MATCHALL_CLASSID:
matchall.ClassId = native.Uint32(datum.Value[0:4])
case nl.TCA_MATCHALL_ACT:
tables, err := nl.ParseRouteAttr(datum.Value)
if err != nil {
return detailed, err
}
matchall.Actions, err = parseActions(tables)
if err != nil {
return detailed, err
}
}
}
return detailed, nil
}
func AlignToAtm(size uint) uint {
var linksize, cells int
cells = int(size / nl.ATM_CELL_PAYLOAD)
@ -562,7 +600,7 @@ func AdjustSize(sz uint, mpu uint, linklayer int) uint {
}
}
func CalcRtable(rate *nl.TcRateSpec, rtab [256]uint32, cellLog int, mtu uint32, linklayer int) int {
func CalcRtable(rate *nl.TcRateSpec, rtab []uint32, cellLog int, mtu uint32, linklayer int) int {
bps := rate.Rate
mpu := rate.Mpu
var sz uint

21
vendor/github.com/vishvananda/netlink/fou.go generated vendored Normal file
View file

@ -0,0 +1,21 @@
package netlink
import (
"errors"
)
var (
// ErrAttrHeaderTruncated is returned when a netlink attribute's header is
// truncated.
ErrAttrHeaderTruncated = errors.New("attribute header truncated")
// ErrAttrBodyTruncated is returned when a netlink attribute's body is
// truncated.
ErrAttrBodyTruncated = errors.New("attribute body truncated")
)
type Fou struct {
Family int
Port int
Protocol int
EncapType int
}

215
vendor/github.com/vishvananda/netlink/fou_linux.go generated vendored Normal file
View file

@ -0,0 +1,215 @@
// +build linux
package netlink
import (
"encoding/binary"
"errors"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
const (
FOU_GENL_NAME = "fou"
)
const (
FOU_CMD_UNSPEC uint8 = iota
FOU_CMD_ADD
FOU_CMD_DEL
FOU_CMD_GET
FOU_CMD_MAX = FOU_CMD_GET
)
const (
FOU_ATTR_UNSPEC = iota
FOU_ATTR_PORT
FOU_ATTR_AF
FOU_ATTR_IPPROTO
FOU_ATTR_TYPE
FOU_ATTR_REMCSUM_NOPARTIAL
FOU_ATTR_MAX = FOU_ATTR_REMCSUM_NOPARTIAL
)
const (
FOU_ENCAP_UNSPEC = iota
FOU_ENCAP_DIRECT
FOU_ENCAP_GUE
FOU_ENCAP_MAX = FOU_ENCAP_GUE
)
var fouFamilyId int
func FouFamilyId() (int, error) {
if fouFamilyId != 0 {
return fouFamilyId, nil
}
fam, err := GenlFamilyGet(FOU_GENL_NAME)
if err != nil {
return -1, err
}
fouFamilyId = int(fam.ID)
return fouFamilyId, nil
}
func FouAdd(f Fou) error {
return pkgHandle.FouAdd(f)
}
func (h *Handle) FouAdd(f Fou) error {
fam_id, err := FouFamilyId()
if err != nil {
return err
}
// setting ip protocol conflicts with encapsulation type GUE
if f.EncapType == FOU_ENCAP_GUE && f.Protocol != 0 {
return errors.New("GUE encapsulation doesn't specify an IP protocol")
}
req := h.newNetlinkRequest(fam_id, unix.NLM_F_ACK)
// int to byte for port
bp := make([]byte, 2)
binary.BigEndian.PutUint16(bp[0:2], uint16(f.Port))
attrs := []*nl.RtAttr{
nl.NewRtAttr(FOU_ATTR_PORT, bp),
nl.NewRtAttr(FOU_ATTR_TYPE, []byte{uint8(f.EncapType)}),
nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(f.Family)}),
nl.NewRtAttr(FOU_ATTR_IPPROTO, []byte{uint8(f.Protocol)}),
}
raw := []byte{FOU_CMD_ADD, 1, 0, 0}
for _, a := range attrs {
raw = append(raw, a.Serialize()...)
}
req.AddRawData(raw)
_, err = req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return err
}
return nil
}
func FouDel(f Fou) error {
return pkgHandle.FouDel(f)
}
func (h *Handle) FouDel(f Fou) error {
fam_id, err := FouFamilyId()
if err != nil {
return err
}
req := h.newNetlinkRequest(fam_id, unix.NLM_F_ACK)
// int to byte for port
bp := make([]byte, 2)
binary.BigEndian.PutUint16(bp[0:2], uint16(f.Port))
attrs := []*nl.RtAttr{
nl.NewRtAttr(FOU_ATTR_PORT, bp),
nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(f.Family)}),
}
raw := []byte{FOU_CMD_DEL, 1, 0, 0}
for _, a := range attrs {
raw = append(raw, a.Serialize()...)
}
req.AddRawData(raw)
_, err = req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return err
}
return nil
}
func FouList(fam int) ([]Fou, error) {
return pkgHandle.FouList(fam)
}
func (h *Handle) FouList(fam int) ([]Fou, error) {
fam_id, err := FouFamilyId()
if err != nil {
return nil, err
}
req := h.newNetlinkRequest(fam_id, unix.NLM_F_DUMP)
attrs := []*nl.RtAttr{
nl.NewRtAttr(FOU_ATTR_AF, []byte{uint8(fam)}),
}
raw := []byte{FOU_CMD_GET, 1, 0, 0}
for _, a := range attrs {
raw = append(raw, a.Serialize()...)
}
req.AddRawData(raw)
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
fous := make([]Fou, 0, len(msgs))
for _, m := range msgs {
f, err := deserializeFouMsg(m)
if err != nil {
return fous, err
}
fous = append(fous, f)
}
return fous, nil
}
func deserializeFouMsg(msg []byte) (Fou, error) {
// we'll skip to byte 4 to first attribute
msg = msg[3:]
var shift int
fou := Fou{}
for {
// attribute header is at least 16 bits
if len(msg) < 4 {
return fou, ErrAttrHeaderTruncated
}
lgt := int(binary.BigEndian.Uint16(msg[0:2]))
if len(msg) < lgt+4 {
return fou, ErrAttrBodyTruncated
}
attr := binary.BigEndian.Uint16(msg[2:4])
shift = lgt + 3
switch attr {
case FOU_ATTR_AF:
fou.Family = int(msg[5])
case FOU_ATTR_PORT:
fou.Port = int(binary.BigEndian.Uint16(msg[5:7]))
// port is 2 bytes
shift = lgt + 2
case FOU_ATTR_IPPROTO:
fou.Protocol = int(msg[5])
case FOU_ATTR_TYPE:
fou.EncapType = int(msg[5])
}
msg = msg[shift:]
if len(msg) < 4 {
break
}
}
return fou, nil
}

View file

@ -0,0 +1,15 @@
// +build !linux
package netlink
func FouAdd(f Fou) error {
return ErrNotImplemented
}
func FouDel(f Fou) error {
return ErrNotImplemented
}
func FouList(fam int) ([]Fou, error) {
return nil, ErrNotImplemented
}

View file

@ -5,6 +5,7 @@ import (
"syscall"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
type GenlOp struct {
@ -130,9 +131,9 @@ func (h *Handle) GenlFamilyList() ([]*GenlFamily, error) {
Command: nl.GENL_CTRL_CMD_GETFAMILY,
Version: nl.GENL_CTRL_VERSION,
}
req := h.newNetlinkRequest(nl.GENL_ID_CTRL, syscall.NLM_F_DUMP)
req := h.newNetlinkRequest(nl.GENL_ID_CTRL, unix.NLM_F_DUMP)
req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
@ -151,7 +152,7 @@ func (h *Handle) GenlFamilyGet(name string) (*GenlFamily, error) {
req := h.newNetlinkRequest(nl.GENL_ID_CTRL, 0)
req.AddData(msg)
req.AddData(nl.NewRtAttr(nl.GENL_CTRL_ATTR_FAMILY_NAME, nl.ZeroTerminated(name)))
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}

View file

@ -7,6 +7,7 @@ import (
"syscall"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
type PDP struct {
@ -82,9 +83,9 @@ func (h *Handle) GTPPDPList() ([]*PDP, error) {
Command: nl.GENL_GTP_CMD_GETPDP,
Version: nl.GENL_GTP_VERSION,
}
req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_DUMP)
req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_DUMP)
req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
@ -96,7 +97,7 @@ func GTPPDPList() ([]*PDP, error) {
}
func gtpPDPGet(req *nl.NetlinkRequest) (*PDP, error) {
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
@ -182,7 +183,7 @@ func (h *Handle) GTPPDPAdd(link Link, pdp *PDP) error {
Command: nl.GENL_GTP_CMD_NEWPDP,
Version: nl.GENL_GTP_VERSION,
}
req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_EXCL|unix.NLM_F_ACK)
req.AddData(msg)
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version)))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
@ -199,7 +200,7 @@ func (h *Handle) GTPPDPAdd(link Link, pdp *PDP) error {
default:
return fmt.Errorf("unsupported GTP version: %d", pdp.Version)
}
_, err = req.Execute(syscall.NETLINK_GENERIC, 0)
_, err = req.Execute(unix.NETLINK_GENERIC, 0)
return err
}
@ -216,7 +217,7 @@ func (h *Handle) GTPPDPDel(link Link, pdp *PDP) error {
Command: nl.GENL_GTP_CMD_DELPDP,
Version: nl.GENL_GTP_VERSION,
}
req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_EXCL|unix.NLM_F_ACK)
req.AddData(msg)
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version)))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
@ -229,7 +230,7 @@ func (h *Handle) GTPPDPDel(link Link, pdp *PDP) error {
default:
return fmt.Errorf("unsupported GTP version: %d", pdp.Version)
}
_, err = req.Execute(syscall.NETLINK_GENERIC, 0)
_, err = req.Execute(unix.NETLINK_GENERIC, 0)
return err
}

View file

@ -2,11 +2,11 @@ package netlink
import (
"fmt"
"syscall"
"time"
"github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
)
// Empty handle used by the netlink package methods
@ -43,7 +43,7 @@ func (h *Handle) SetSocketTimeout(to time.Duration) error {
if to < time.Microsecond {
return fmt.Errorf("invalid timeout, minimul value is %s", time.Microsecond)
}
tv := syscall.NsecToTimeval(to.Nanoseconds())
tv := unix.NsecToTimeval(to.Nanoseconds())
for _, sh := range h.sockets {
if err := sh.Socket.SetSendTimeout(&tv); err != nil {
return err
@ -59,13 +59,13 @@ func (h *Handle) SetSocketTimeout(to time.Duration) error {
// socket in the netlink handle. The maximum value is capped by
// /proc/sys/net/core/rmem_max.
func (h *Handle) SetSocketReceiveBufferSize(size int, force bool) error {
opt := syscall.SO_RCVBUF
opt := unix.SO_RCVBUF
if force {
opt = syscall.SO_RCVBUFFORCE
opt = unix.SO_RCVBUFFORCE
}
for _, sh := range h.sockets {
fd := sh.Socket.GetFd()
err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, opt, size)
err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, opt, size)
if err != nil {
return err
}
@ -81,7 +81,7 @@ func (h *Handle) GetSocketReceiveBufferSize() ([]int, error) {
i := 0
for _, sh := range h.sockets {
fd := sh.Socket.GetFd()
size, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF)
size, err := unix.GetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_RCVBUF)
if err != nil {
return nil, err
}
@ -134,10 +134,10 @@ func (h *Handle) newNetlinkRequest(proto, flags int) *nl.NetlinkRequest {
return nl.NewNetlinkRequest(proto, flags)
}
return &nl.NetlinkRequest{
NlMsghdr: syscall.NlMsghdr{
Len: uint32(syscall.SizeofNlMsghdr),
NlMsghdr: unix.NlMsghdr{
Len: uint32(unix.SizeofNlMsghdr),
Type: uint16(proto),
Flags: syscall.NLM_F_REQUEST | uint16(flags),
Flags: unix.NLM_F_REQUEST | uint16(flags),
},
Sockets: h.sockets,
}

View file

@ -220,3 +220,39 @@ func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
return nil, ErrNotImplemented
}
func (h *Handle) RouteAdd(route *Route) error {
return ErrNotImplemented
}
func (h *Handle) RouteDel(route *Route) error {
return ErrNotImplemented
}
func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
return nil, ErrNotImplemented
}
func (h *Handle) RouteList(link Link, family int) ([]Route, error) {
return nil, ErrNotImplemented
}
func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
return nil, ErrNotImplemented
}
func (h *Handle) RouteReplace(route *Route) error {
return ErrNotImplemented
}
func (h *Handle) RuleAdd(rule *Rule) error {
return ErrNotImplemented
}
func (h *Handle) RuleDel(rule *Rule) error {
return ErrNotImplemented
}
func (h *Handle) RuleList(family int) ([]Rule, error) {
return nil, ErrNotImplemented
}

98
vendor/github.com/vishvananda/netlink/ioctl_linux.go generated vendored Normal file
View file

@ -0,0 +1,98 @@
package netlink
import (
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
// ioctl for statistics.
const (
// ETHTOOL_GSSET_INFO gets string set info
ETHTOOL_GSSET_INFO = 0x00000037
// SIOCETHTOOL is Ethtool interface
SIOCETHTOOL = 0x8946
// ETHTOOL_GSTRINGS gets specified string set
ETHTOOL_GSTRINGS = 0x0000001b
// ETHTOOL_GSTATS gets NIC-specific statistics
ETHTOOL_GSTATS = 0x0000001d
)
// string set id.
const (
// ETH_SS_TEST is self-test result names, for use with %ETHTOOL_TEST
ETH_SS_TEST = iota
// ETH_SS_STATS statistic names, for use with %ETHTOOL_GSTATS
ETH_SS_STATS
// ETH_SS_PRIV_FLAGS are driver private flag names
ETH_SS_PRIV_FLAGS
// _ETH_SS_NTUPLE_FILTERS is deprecated
_ETH_SS_NTUPLE_FILTERS
// ETH_SS_FEATURES are device feature names
ETH_SS_FEATURES
// ETH_SS_RSS_HASH_FUNCS is RSS hush function names
ETH_SS_RSS_HASH_FUNCS
)
// IfreqSlave is a struct for ioctl bond manipulation syscalls.
// It is used to assign slave to bond interface with Name.
type IfreqSlave struct {
Name [unix.IFNAMSIZ]byte
Slave [unix.IFNAMSIZ]byte
}
// Ifreq is a struct for ioctl ethernet manipulation syscalls.
type Ifreq struct {
Name [unix.IFNAMSIZ]byte
Data uintptr
}
// ethtoolSset is a string set information
type ethtoolSset struct {
cmd uint32
reserved uint32
mask uint64
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
}
// newIocltSlaveReq returns filled IfreqSlave with proper interface names
// It is used by ioctl to assign slave to bond master
func newIocltSlaveReq(slave, master string) *IfreqSlave {
ifreq := &IfreqSlave{}
copy(ifreq.Name[:unix.IFNAMSIZ-1], master)
copy(ifreq.Slave[:unix.IFNAMSIZ-1], slave)
return ifreq
}
// newIocltStringSetReq creates request to get interface string set
func newIocltStringSetReq(linkName string) (*Ifreq, *ethtoolSset) {
e := &ethtoolSset{
cmd: ETHTOOL_GSSET_INFO,
mask: 1 << ETH_SS_STATS,
}
ifreq := &Ifreq{Data: uintptr(unsafe.Pointer(e))}
copy(ifreq.Name[:unix.IFNAMSIZ-1], linkName)
return ifreq, e
}
// getSocketUDP returns file descriptor to new UDP socket
// It is used for communication with ioctl interface.
func getSocketUDP() (int, error) {
return syscall.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
}

View file

@ -3,6 +3,7 @@ package netlink
import (
"fmt"
"net"
"os"
)
// Link represents a link device from netlink. Shared link attributes
@ -38,6 +39,8 @@ type LinkAttrs struct {
Protinfo *Protinfo
OperState LinkOperState
NetNsID int
NumTxQueues int
NumRxQueues int
}
// LinkOperState represents the values of the IFLA_OPERSTATE link
@ -259,6 +262,9 @@ const (
type Macvlan struct {
LinkAttrs
Mode MacvlanMode
// MACAddrs is only populated for Macvlan SOURCE links
MACAddrs []net.HardwareAddr
}
func (macvlan *Macvlan) Attrs() *LinkAttrs {
@ -284,8 +290,10 @@ type TuntapFlag uint16
// Tuntap links created via /dev/tun/tap, but can be destroyed via netlink
type Tuntap struct {
LinkAttrs
Mode TuntapMode
Flags TuntapFlag
Mode TuntapMode
Flags TuntapFlag
Queues int
Fds []*os.File
}
func (tuntap *Tuntap) Attrs() *LinkAttrs {
@ -327,26 +335,28 @@ func (generic *GenericLink) Type() string {
type Vxlan struct {
LinkAttrs
VxlanId int
VtepDevIndex int
SrcAddr net.IP
Group net.IP
TTL int
TOS int
Learning bool
Proxy bool
RSC bool
L2miss bool
L3miss bool
UDPCSum bool
NoAge bool
GBP bool
FlowBased bool
Age int
Limit int
Port int
PortLow int
PortHigh int
VxlanId int
VtepDevIndex int
SrcAddr net.IP
Group net.IP
TTL int
TOS int
Learning bool
Proxy bool
RSC bool
L2miss bool
L3miss bool
UDPCSum bool
UDP6ZeroCSumTx bool
UDP6ZeroCSumRx bool
NoAge bool
GBP bool
FlowBased bool
Age int
Limit int
Port int
PortLow int
PortHigh int
}
func (vxlan *Vxlan) Attrs() *LinkAttrs {
@ -695,17 +705,25 @@ func (gretap *Gretap) Attrs() *LinkAttrs {
}
func (gretap *Gretap) Type() string {
if gretap.Local.To4() == nil {
return "ip6gretap"
}
return "gretap"
}
type Iptun struct {
LinkAttrs
Ttl uint8
Tos uint8
PMtuDisc uint8
Link uint32
Local net.IP
Remote net.IP
Ttl uint8
Tos uint8
PMtuDisc uint8
Link uint32
Local net.IP
Remote net.IP
EncapSport uint16
EncapDport uint16
EncapType uint16
EncapFlags uint16
FlowBased bool
}
func (iptun *Iptun) Attrs() *LinkAttrs {
@ -716,6 +734,28 @@ func (iptun *Iptun) Type() string {
return "ipip"
}
type Sittun struct {
LinkAttrs
Link uint32
Local net.IP
Remote net.IP
Ttl uint8
Tos uint8
PMtuDisc uint8
EncapType uint16
EncapFlags uint16
EncapSport uint16
EncapDport uint16
}
func (sittun *Sittun) Attrs() *LinkAttrs {
return &sittun.LinkAttrs
}
func (sittun *Sittun) Type() string {
return "sit"
}
type Vti struct {
LinkAttrs
IKey uint32
@ -735,16 +775,20 @@ func (iptun *Vti) Type() string {
type Gretun struct {
LinkAttrs
Link uint32
IFlags uint16
OFlags uint16
IKey uint32
OKey uint32
Local net.IP
Remote net.IP
Ttl uint8
Tos uint8
PMtuDisc uint8
Link uint32
IFlags uint16
OFlags uint16
IKey uint32
OKey uint32
Local net.IP
Remote net.IP
Ttl uint8
Tos uint8
PMtuDisc uint8
EncapType uint16
EncapFlags uint16
EncapSport uint16
EncapDport uint16
}
func (gretun *Gretun) Attrs() *LinkAttrs {
@ -752,6 +796,9 @@ func (gretun *Gretun) Attrs() *LinkAttrs {
}
func (gretun *Gretun) Type() string {
if gretun.Local.To4() == nil {
return "ip6gre"
}
return "gre"
}

File diff suppressed because it is too large Load diff

View file

@ -15,6 +15,8 @@ type Neigh struct {
IP net.IP
HardwareAddr net.HardwareAddr
LLIPAddr net.IP //Used in the case of NHRP
Vlan int
VNI int
}
// String returns $ip/$hwaddr $label

View file

@ -2,10 +2,10 @@ package netlink
import (
"net"
"syscall"
"unsafe"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
const (
@ -73,7 +73,7 @@ func NeighAdd(neigh *Neigh) error {
// NeighAdd will add an IP to MAC mapping to the ARP table
// Equivalent to: `ip neigh add ....`
func (h *Handle) NeighAdd(neigh *Neigh) error {
return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL)
return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_EXCL)
}
// NeighSet will add or replace an IP to MAC mapping to the ARP table
@ -85,7 +85,7 @@ func NeighSet(neigh *Neigh) error {
// NeighSet will add or replace an IP to MAC mapping to the ARP table
// Equivalent to: `ip neigh replace....`
func (h *Handle) NeighSet(neigh *Neigh) error {
return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE)
return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_REPLACE)
}
// NeighAppend will append an entry to FDB
@ -97,7 +97,7 @@ func NeighAppend(neigh *Neigh) error {
// NeighAppend will append an entry to FDB
// Equivalent to: `bridge fdb append...`
func (h *Handle) NeighAppend(neigh *Neigh) error {
return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_APPEND)
return h.neighAdd(neigh, unix.NLM_F_CREATE|unix.NLM_F_APPEND)
}
// NeighAppend will append an entry to FDB
@ -109,7 +109,7 @@ func neighAdd(neigh *Neigh, mode int) error {
// NeighAppend will append an entry to FDB
// Equivalent to: `bridge fdb append...`
func (h *Handle) neighAdd(neigh *Neigh, mode int) error {
req := h.newNetlinkRequest(syscall.RTM_NEWNEIGH, mode|syscall.NLM_F_ACK)
req := h.newNetlinkRequest(unix.RTM_NEWNEIGH, mode|unix.NLM_F_ACK)
return neighHandle(neigh, req)
}
@ -122,7 +122,7 @@ func NeighDel(neigh *Neigh) error {
// NeighDel will delete an IP address from a link device.
// Equivalent to: `ip addr del $addr dev $link`
func (h *Handle) NeighDel(neigh *Neigh) error {
req := h.newNetlinkRequest(syscall.RTM_DELNEIGH, syscall.NLM_F_ACK)
req := h.newNetlinkRequest(unix.RTM_DELNEIGH, unix.NLM_F_ACK)
return neighHandle(neigh, req)
}
@ -160,7 +160,17 @@ func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
req.AddData(hwData)
}
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
if neigh.Vlan != 0 {
vlanData := nl.NewRtAttr(NDA_VLAN, nl.Uint16Attr(uint16(neigh.Vlan)))
req.AddData(vlanData)
}
if neigh.VNI != 0 {
vniData := nl.NewRtAttr(NDA_VNI, nl.Uint32Attr(uint32(neigh.VNI)))
req.AddData(vniData)
}
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
@ -193,7 +203,7 @@ func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
}
func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) {
req := h.newNetlinkRequest(syscall.RTM_GETNEIGH, syscall.NLM_F_DUMP)
req := h.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP)
msg := Ndmsg{
Family: uint8(family),
Index: uint32(linkIndex),
@ -201,7 +211,7 @@ func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) {
}
req.AddData(&msg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWNEIGH)
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH)
if err != nil {
return nil, err
}
@ -257,7 +267,7 @@ func NeighDeserialize(m []byte) (*Neigh, error) {
// BUG: Is this a bug in the netlink library?
// #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 - syscall.SizeofRtAttr
attrLen := attr.Attr.Len - unix.SizeofRtAttr
if attrLen == 4 && (encapType == "ipip" ||
encapType == "sit" ||
encapType == "gre") {
@ -268,6 +278,10 @@ func NeighDeserialize(m []byte) (*Neigh, error) {
} else {
neigh.HardwareAddr = net.HardwareAddr(attr.Value)
}
case NDA_VLAN:
neigh.Vlan = int(native.Uint16(attr.Value[0:2]))
case NDA_VNI:
neigh.VNI = int(native.Uint32(attr.Value[0:4]))
}
}

View file

@ -1,17 +1,18 @@
package nl
import (
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
type IfAddrmsg struct {
syscall.IfAddrmsg
unix.IfAddrmsg
}
func NewIfAddrmsg(family int) *IfAddrmsg {
return &IfAddrmsg{
IfAddrmsg: syscall.IfAddrmsg{
IfAddrmsg: unix.IfAddrmsg{
Family: uint8(family),
},
}
@ -35,15 +36,15 @@ func NewIfAddrmsg(family int) *IfAddrmsg {
// SizeofIfAddrmsg = 0x8
func DeserializeIfAddrmsg(b []byte) *IfAddrmsg {
return (*IfAddrmsg)(unsafe.Pointer(&b[0:syscall.SizeofIfAddrmsg][0]))
return (*IfAddrmsg)(unsafe.Pointer(&b[0:unix.SizeofIfAddrmsg][0]))
}
func (msg *IfAddrmsg) Serialize() []byte {
return (*(*[syscall.SizeofIfAddrmsg]byte)(unsafe.Pointer(msg)))[:]
return (*(*[unix.SizeofIfAddrmsg]byte)(unsafe.Pointer(msg)))[:]
}
func (msg *IfAddrmsg) Len() int {
return syscall.SizeofIfAddrmsg
return unix.SizeofIfAddrmsg
}
// struct ifa_cacheinfo {

View file

@ -1,35 +1,11 @@
package nl
import (
"syscall"
"unsafe"
)
const (
DEFAULT_CHANGE = 0xFFFFFFFF
// doesn't exist in syscall
IFLA_VFINFO_LIST = syscall.IFLA_IFALIAS + 1 + iota
IFLA_STATS64
IFLA_VF_PORTS
IFLA_PORT_SELF
IFLA_AF_SPEC
IFLA_GROUP
IFLA_NET_NS_FD
IFLA_EXT_MASK
IFLA_PROMISCUITY
IFLA_NUM_TX_QUEUES
IFLA_NUM_RX_QUEUES
IFLA_CARRIER
IFLA_PHYS_PORT_ID
IFLA_CARRIER_CHANGES
IFLA_PHYS_SWITCH_ID
IFLA_LINK_NETNSID
IFLA_PHYS_PORT_NAME
IFLA_PROTO_DOWN
IFLA_GSO_MAX_SEGS
IFLA_GSO_MAX_SIZE
IFLA_PAD
IFLA_XDP
)
const (
@ -118,6 +94,10 @@ const (
IFLA_MACVLAN_UNSPEC = iota
IFLA_MACVLAN_MODE
IFLA_MACVLAN_FLAGS
IFLA_MACVLAN_MACADDR_MODE
IFLA_MACVLAN_MACADDR
IFLA_MACVLAN_MACADDR_DATA
IFLA_MACVLAN_MACADDR_COUNT
IFLA_MACVLAN_MAX = IFLA_MACVLAN_FLAGS
)
@ -129,6 +109,13 @@ const (
MACVLAN_MODE_SOURCE = 16
)
const (
MACVLAN_MACADDR_ADD = iota
MACVLAN_MACADDR_DEL
MACVLAN_MACADDR_FLUSH
MACVLAN_MACADDR_SET
)
const (
IFLA_BOND_UNSPEC = iota
IFLA_BOND_MODE
@ -475,7 +462,12 @@ const (
IFLA_IPTUN_6RD_RELAY_PREFIX
IFLA_IPTUN_6RD_PREFIXLEN
IFLA_IPTUN_6RD_RELAY_PREFIXLEN
IFLA_IPTUN_MAX = IFLA_IPTUN_6RD_RELAY_PREFIXLEN
IFLA_IPTUN_ENCAP_TYPE
IFLA_IPTUN_ENCAP_FLAGS
IFLA_IPTUN_ENCAP_SPORT
IFLA_IPTUN_ENCAP_DPORT
IFLA_IPTUN_COLLECT_METADATA
IFLA_IPTUN_MAX = IFLA_IPTUN_COLLECT_METADATA
)
const (

View file

@ -13,18 +13,19 @@ import (
"unsafe"
"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
)
const (
// Family type definitions
FAMILY_ALL = syscall.AF_UNSPEC
FAMILY_V4 = syscall.AF_INET
FAMILY_V6 = syscall.AF_INET6
FAMILY_ALL = unix.AF_UNSPEC
FAMILY_V4 = unix.AF_INET
FAMILY_V6 = unix.AF_INET6
FAMILY_MPLS = AF_MPLS
)
// SupportedNlFamilies contains the list of netlink families this netlink package supports
var SupportedNlFamilies = []int{syscall.NETLINK_ROUTE, syscall.NETLINK_XFRM, syscall.NETLINK_NETFILTER}
var SupportedNlFamilies = []int{unix.NETLINK_ROUTE, unix.NETLINK_XFRM, unix.NETLINK_NETFILTER}
var nextSeqNr uint32
@ -77,161 +78,161 @@ type NetlinkRequestData interface {
// IfInfomsg is related to links, but it is used for list requests as well
type IfInfomsg struct {
syscall.IfInfomsg
unix.IfInfomsg
}
// Create an IfInfomsg with family specified
func NewIfInfomsg(family int) *IfInfomsg {
return &IfInfomsg{
IfInfomsg: syscall.IfInfomsg{
IfInfomsg: unix.IfInfomsg{
Family: uint8(family),
},
}
}
func DeserializeIfInfomsg(b []byte) *IfInfomsg {
return (*IfInfomsg)(unsafe.Pointer(&b[0:syscall.SizeofIfInfomsg][0]))
return (*IfInfomsg)(unsafe.Pointer(&b[0:unix.SizeofIfInfomsg][0]))
}
func (msg *IfInfomsg) Serialize() []byte {
return (*(*[syscall.SizeofIfInfomsg]byte)(unsafe.Pointer(msg)))[:]
return (*(*[unix.SizeofIfInfomsg]byte)(unsafe.Pointer(msg)))[:]
}
func (msg *IfInfomsg) Len() int {
return syscall.SizeofIfInfomsg
return unix.SizeofIfInfomsg
}
func (msg *IfInfomsg) EncapType() string {
switch msg.Type {
case 0:
return "generic"
case syscall.ARPHRD_ETHER:
case unix.ARPHRD_ETHER:
return "ether"
case syscall.ARPHRD_EETHER:
case unix.ARPHRD_EETHER:
return "eether"
case syscall.ARPHRD_AX25:
case unix.ARPHRD_AX25:
return "ax25"
case syscall.ARPHRD_PRONET:
case unix.ARPHRD_PRONET:
return "pronet"
case syscall.ARPHRD_CHAOS:
case unix.ARPHRD_CHAOS:
return "chaos"
case syscall.ARPHRD_IEEE802:
case unix.ARPHRD_IEEE802:
return "ieee802"
case syscall.ARPHRD_ARCNET:
case unix.ARPHRD_ARCNET:
return "arcnet"
case syscall.ARPHRD_APPLETLK:
case unix.ARPHRD_APPLETLK:
return "atalk"
case syscall.ARPHRD_DLCI:
case unix.ARPHRD_DLCI:
return "dlci"
case syscall.ARPHRD_ATM:
case unix.ARPHRD_ATM:
return "atm"
case syscall.ARPHRD_METRICOM:
case unix.ARPHRD_METRICOM:
return "metricom"
case syscall.ARPHRD_IEEE1394:
case unix.ARPHRD_IEEE1394:
return "ieee1394"
case syscall.ARPHRD_INFINIBAND:
case unix.ARPHRD_INFINIBAND:
return "infiniband"
case syscall.ARPHRD_SLIP:
case unix.ARPHRD_SLIP:
return "slip"
case syscall.ARPHRD_CSLIP:
case unix.ARPHRD_CSLIP:
return "cslip"
case syscall.ARPHRD_SLIP6:
case unix.ARPHRD_SLIP6:
return "slip6"
case syscall.ARPHRD_CSLIP6:
case unix.ARPHRD_CSLIP6:
return "cslip6"
case syscall.ARPHRD_RSRVD:
case unix.ARPHRD_RSRVD:
return "rsrvd"
case syscall.ARPHRD_ADAPT:
case unix.ARPHRD_ADAPT:
return "adapt"
case syscall.ARPHRD_ROSE:
case unix.ARPHRD_ROSE:
return "rose"
case syscall.ARPHRD_X25:
case unix.ARPHRD_X25:
return "x25"
case syscall.ARPHRD_HWX25:
case unix.ARPHRD_HWX25:
return "hwx25"
case syscall.ARPHRD_PPP:
case unix.ARPHRD_PPP:
return "ppp"
case syscall.ARPHRD_HDLC:
case unix.ARPHRD_HDLC:
return "hdlc"
case syscall.ARPHRD_LAPB:
case unix.ARPHRD_LAPB:
return "lapb"
case syscall.ARPHRD_DDCMP:
case unix.ARPHRD_DDCMP:
return "ddcmp"
case syscall.ARPHRD_RAWHDLC:
case unix.ARPHRD_RAWHDLC:
return "rawhdlc"
case syscall.ARPHRD_TUNNEL:
case unix.ARPHRD_TUNNEL:
return "ipip"
case syscall.ARPHRD_TUNNEL6:
case unix.ARPHRD_TUNNEL6:
return "tunnel6"
case syscall.ARPHRD_FRAD:
case unix.ARPHRD_FRAD:
return "frad"
case syscall.ARPHRD_SKIP:
case unix.ARPHRD_SKIP:
return "skip"
case syscall.ARPHRD_LOOPBACK:
case unix.ARPHRD_LOOPBACK:
return "loopback"
case syscall.ARPHRD_LOCALTLK:
case unix.ARPHRD_LOCALTLK:
return "ltalk"
case syscall.ARPHRD_FDDI:
case unix.ARPHRD_FDDI:
return "fddi"
case syscall.ARPHRD_BIF:
case unix.ARPHRD_BIF:
return "bif"
case syscall.ARPHRD_SIT:
case unix.ARPHRD_SIT:
return "sit"
case syscall.ARPHRD_IPDDP:
case unix.ARPHRD_IPDDP:
return "ip/ddp"
case syscall.ARPHRD_IPGRE:
case unix.ARPHRD_IPGRE:
return "gre"
case syscall.ARPHRD_PIMREG:
case unix.ARPHRD_PIMREG:
return "pimreg"
case syscall.ARPHRD_HIPPI:
case unix.ARPHRD_HIPPI:
return "hippi"
case syscall.ARPHRD_ASH:
case unix.ARPHRD_ASH:
return "ash"
case syscall.ARPHRD_ECONET:
case unix.ARPHRD_ECONET:
return "econet"
case syscall.ARPHRD_IRDA:
case unix.ARPHRD_IRDA:
return "irda"
case syscall.ARPHRD_FCPP:
case unix.ARPHRD_FCPP:
return "fcpp"
case syscall.ARPHRD_FCAL:
case unix.ARPHRD_FCAL:
return "fcal"
case syscall.ARPHRD_FCPL:
case unix.ARPHRD_FCPL:
return "fcpl"
case syscall.ARPHRD_FCFABRIC:
case unix.ARPHRD_FCFABRIC:
return "fcfb0"
case syscall.ARPHRD_FCFABRIC + 1:
case unix.ARPHRD_FCFABRIC + 1:
return "fcfb1"
case syscall.ARPHRD_FCFABRIC + 2:
case unix.ARPHRD_FCFABRIC + 2:
return "fcfb2"
case syscall.ARPHRD_FCFABRIC + 3:
case unix.ARPHRD_FCFABRIC + 3:
return "fcfb3"
case syscall.ARPHRD_FCFABRIC + 4:
case unix.ARPHRD_FCFABRIC + 4:
return "fcfb4"
case syscall.ARPHRD_FCFABRIC + 5:
case unix.ARPHRD_FCFABRIC + 5:
return "fcfb5"
case syscall.ARPHRD_FCFABRIC + 6:
case unix.ARPHRD_FCFABRIC + 6:
return "fcfb6"
case syscall.ARPHRD_FCFABRIC + 7:
case unix.ARPHRD_FCFABRIC + 7:
return "fcfb7"
case syscall.ARPHRD_FCFABRIC + 8:
case unix.ARPHRD_FCFABRIC + 8:
return "fcfb8"
case syscall.ARPHRD_FCFABRIC + 9:
case unix.ARPHRD_FCFABRIC + 9:
return "fcfb9"
case syscall.ARPHRD_FCFABRIC + 10:
case unix.ARPHRD_FCFABRIC + 10:
return "fcfb10"
case syscall.ARPHRD_FCFABRIC + 11:
case unix.ARPHRD_FCFABRIC + 11:
return "fcfb11"
case syscall.ARPHRD_FCFABRIC + 12:
case unix.ARPHRD_FCFABRIC + 12:
return "fcfb12"
case syscall.ARPHRD_IEEE802_TR:
case unix.ARPHRD_IEEE802_TR:
return "tr"
case syscall.ARPHRD_IEEE80211:
case unix.ARPHRD_IEEE80211:
return "ieee802.11"
case syscall.ARPHRD_IEEE80211_PRISM:
case unix.ARPHRD_IEEE80211_PRISM:
return "ieee802.11/prism"
case syscall.ARPHRD_IEEE80211_RADIOTAP:
case unix.ARPHRD_IEEE80211_RADIOTAP:
return "ieee802.11/radiotap"
case syscall.ARPHRD_IEEE802154:
case unix.ARPHRD_IEEE802154:
return "ieee802.15.4"
case 65534:
@ -243,7 +244,7 @@ func (msg *IfInfomsg) EncapType() string {
}
func rtaAlignOf(attrlen int) int {
return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1)
return (attrlen + unix.RTA_ALIGNTO - 1) & ^(unix.RTA_ALIGNTO - 1)
}
func NewIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
@ -254,7 +255,7 @@ func NewIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
// Extend RtAttr to handle data and children
type RtAttr struct {
syscall.RtAttr
unix.RtAttr
Data []byte
children []NetlinkRequestData
}
@ -262,7 +263,7 @@ type RtAttr struct {
// Create a new Extended RtAttr object
func NewRtAttr(attrType int, data []byte) *RtAttr {
return &RtAttr{
RtAttr: syscall.RtAttr{
RtAttr: unix.RtAttr{
Type: uint16(attrType),
},
children: []NetlinkRequestData{},
@ -277,16 +278,21 @@ func NewRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr {
return attr
}
// AddChild adds an existing RtAttr as a child.
func (a *RtAttr) AddChild(attr *RtAttr) {
a.children = append(a.children, attr)
}
func (a *RtAttr) Len() int {
if len(a.children) == 0 {
return (syscall.SizeofRtAttr + len(a.Data))
return (unix.SizeofRtAttr + len(a.Data))
}
l := 0
for _, child := range a.children {
l += rtaAlignOf(child.Len())
}
l += syscall.SizeofRtAttr
l += unix.SizeofRtAttr
return rtaAlignOf(l + len(a.Data))
}
@ -319,7 +325,7 @@ func (a *RtAttr) Serialize() []byte {
}
type NetlinkRequest struct {
syscall.NlMsghdr
unix.NlMsghdr
Data []NetlinkRequestData
RawData []byte
Sockets map[int]*SocketHandle
@ -327,7 +333,7 @@ type NetlinkRequest struct {
// Serialize the Netlink Request into a byte array
func (req *NetlinkRequest) Serialize() []byte {
length := syscall.SizeofNlMsghdr
length := unix.SizeofNlMsghdr
dataBytes := make([][]byte, len(req.Data))
for i, data := range req.Data {
dataBytes[i] = data.Serialize()
@ -337,8 +343,8 @@ func (req *NetlinkRequest) Serialize() []byte {
req.Len = uint32(length)
b := make([]byte, length)
hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:]
next := syscall.SizeofNlMsghdr
hdr := (*(*[unix.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:]
next := unix.SizeofNlMsghdr
copy(b[0:next], hdr)
for _, data := range dataBytes {
for _, dataByte := range data {
@ -421,10 +427,10 @@ done:
if m.Header.Pid != pid {
return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
}
if m.Header.Type == syscall.NLMSG_DONE {
if m.Header.Type == unix.NLMSG_DONE {
break done
}
if m.Header.Type == syscall.NLMSG_ERROR {
if m.Header.Type == unix.NLMSG_ERROR {
native := NativeEndian()
error := int32(native.Uint32(m.Data[0:4]))
if error == 0 {
@ -436,7 +442,7 @@ done:
continue
}
res = append(res, m.Data)
if m.Header.Flags&syscall.NLM_F_MULTI == 0 {
if m.Header.Flags&unix.NLM_F_MULTI == 0 {
break done
}
}
@ -449,10 +455,10 @@ done:
// the message is serialized
func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
return &NetlinkRequest{
NlMsghdr: syscall.NlMsghdr{
Len: uint32(syscall.SizeofNlMsghdr),
NlMsghdr: unix.NlMsghdr{
Len: uint32(unix.SizeofNlMsghdr),
Type: uint16(proto),
Flags: syscall.NLM_F_REQUEST | uint16(flags),
Flags: unix.NLM_F_REQUEST | uint16(flags),
Seq: atomic.AddUint32(&nextSeqNr, 1),
},
}
@ -460,21 +466,21 @@ func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
type NetlinkSocket struct {
fd int32
lsa syscall.SockaddrNetlink
lsa unix.SockaddrNetlink
sync.Mutex
}
func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW|syscall.SOCK_CLOEXEC, protocol)
fd, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_RAW|unix.SOCK_CLOEXEC, protocol)
if err != nil {
return nil, err
}
s := &NetlinkSocket{
fd: int32(fd),
}
s.lsa.Family = syscall.AF_NETLINK
if err := syscall.Bind(fd, &s.lsa); err != nil {
syscall.Close(fd)
s.lsa.Family = unix.AF_NETLINK
if err := unix.Bind(fd, &s.lsa); err != nil {
unix.Close(fd)
return nil, err
}
@ -551,21 +557,21 @@ func executeInNetns(newNs, curNs netns.NsHandle) (func(), error) {
// Returns the netlink socket on which Receive() method can be called
// to retrieve the messages from the kernel.
func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol)
fd, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_RAW, protocol)
if err != nil {
return nil, err
}
s := &NetlinkSocket{
fd: int32(fd),
}
s.lsa.Family = syscall.AF_NETLINK
s.lsa.Family = unix.AF_NETLINK
for _, g := range groups {
s.lsa.Groups |= (1 << (g - 1))
}
if err := syscall.Bind(fd, &s.lsa); err != nil {
syscall.Close(fd)
if err := unix.Bind(fd, &s.lsa); err != nil {
unix.Close(fd)
return nil, err
}
@ -586,7 +592,7 @@ func SubscribeAt(newNs, curNs netns.NsHandle, protocol int, groups ...uint) (*Ne
func (s *NetlinkSocket) Close() {
fd := int(atomic.SwapInt32(&s.fd, -1))
syscall.Close(fd)
unix.Close(fd)
}
func (s *NetlinkSocket) GetFd() int {
@ -598,7 +604,7 @@ func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
if fd < 0 {
return fmt.Errorf("Send called on a closed socket")
}
if err := syscall.Sendto(fd, request.Serialize(), 0, &s.lsa); err != nil {
if err := unix.Sendto(fd, request.Serialize(), 0, &s.lsa); err != nil {
return err
}
return nil
@ -609,12 +615,12 @@ func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
if fd < 0 {
return nil, fmt.Errorf("Receive called on a closed socket")
}
rb := make([]byte, syscall.Getpagesize())
nr, _, err := syscall.Recvfrom(fd, rb, 0)
rb := make([]byte, unix.Getpagesize())
nr, _, err := unix.Recvfrom(fd, rb, 0)
if err != nil {
return nil, err
}
if nr < syscall.NLMSG_HDRLEN {
if nr < unix.NLMSG_HDRLEN {
return nil, fmt.Errorf("Got short response from netlink")
}
rb = rb[:nr]
@ -622,27 +628,27 @@ func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
}
// SetSendTimeout allows to set a send timeout on the socket
func (s *NetlinkSocket) SetSendTimeout(timeout *syscall.Timeval) error {
func (s *NetlinkSocket) SetSendTimeout(timeout *unix.Timeval) error {
// Set a send timeout of SOCKET_SEND_TIMEOUT, this will allow the Send to periodically unblock and avoid that a routine
// remains stuck on a send on a closed fd
return syscall.SetsockoptTimeval(int(s.fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, timeout)
return unix.SetsockoptTimeval(int(s.fd), unix.SOL_SOCKET, unix.SO_SNDTIMEO, timeout)
}
// SetReceiveTimeout allows to set a receive timeout on the socket
func (s *NetlinkSocket) SetReceiveTimeout(timeout *syscall.Timeval) error {
func (s *NetlinkSocket) SetReceiveTimeout(timeout *unix.Timeval) error {
// Set a read timeout of SOCKET_READ_TIMEOUT, this will allow the Read to periodically unblock and avoid that a routine
// remains stuck on a recvmsg on a closed fd
return syscall.SetsockoptTimeval(int(s.fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, timeout)
return unix.SetsockoptTimeval(int(s.fd), unix.SOL_SOCKET, unix.SO_RCVTIMEO, timeout)
}
func (s *NetlinkSocket) GetPid() (uint32, error) {
fd := int(atomic.LoadInt32(&s.fd))
lsa, err := syscall.Getsockname(fd)
lsa, err := unix.Getsockname(fd)
if err != nil {
return 0, err
}
switch v := lsa.(type) {
case *syscall.SockaddrNetlink:
case *unix.SockaddrNetlink:
return v.Pid, nil
}
return 0, fmt.Errorf("Wrong socket type")
@ -697,24 +703,24 @@ func Uint64Attr(v uint64) []byte {
func ParseRouteAttr(b []byte) ([]syscall.NetlinkRouteAttr, error) {
var attrs []syscall.NetlinkRouteAttr
for len(b) >= syscall.SizeofRtAttr {
for len(b) >= unix.SizeofRtAttr {
a, vbuf, alen, err := netlinkRouteAttrAndValue(b)
if err != nil {
return nil, err
}
ra := syscall.NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-syscall.SizeofRtAttr]}
ra := syscall.NetlinkRouteAttr{Attr: syscall.RtAttr(*a), Value: vbuf[:int(a.Len)-unix.SizeofRtAttr]}
attrs = append(attrs, ra)
b = b[alen:]
}
return attrs, nil
}
func netlinkRouteAttrAndValue(b []byte) (*syscall.RtAttr, []byte, int, error) {
a := (*syscall.RtAttr)(unsafe.Pointer(&b[0]))
if int(a.Len) < syscall.SizeofRtAttr || int(a.Len) > len(b) {
return nil, nil, 0, syscall.EINVAL
func netlinkRouteAttrAndValue(b []byte) (*unix.RtAttr, []byte, int, error) {
a := (*unix.RtAttr)(unsafe.Pointer(&b[0]))
if int(a.Len) < unix.SizeofRtAttr || int(a.Len) > len(b) {
return nil, nil, 0, unix.EINVAL
}
return a, b[syscall.SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil
return a, b[unix.SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil
}
// SocketHandle contains the netlink socket and the associated

View file

@ -1,65 +1,66 @@
package nl
import (
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
type RtMsg struct {
syscall.RtMsg
unix.RtMsg
}
func NewRtMsg() *RtMsg {
return &RtMsg{
RtMsg: syscall.RtMsg{
Table: syscall.RT_TABLE_MAIN,
Scope: syscall.RT_SCOPE_UNIVERSE,
Protocol: syscall.RTPROT_BOOT,
Type: syscall.RTN_UNICAST,
RtMsg: unix.RtMsg{
Table: unix.RT_TABLE_MAIN,
Scope: unix.RT_SCOPE_UNIVERSE,
Protocol: unix.RTPROT_BOOT,
Type: unix.RTN_UNICAST,
},
}
}
func NewRtDelMsg() *RtMsg {
return &RtMsg{
RtMsg: syscall.RtMsg{
Table: syscall.RT_TABLE_MAIN,
Scope: syscall.RT_SCOPE_NOWHERE,
RtMsg: unix.RtMsg{
Table: unix.RT_TABLE_MAIN,
Scope: unix.RT_SCOPE_NOWHERE,
},
}
}
func (msg *RtMsg) Len() int {
return syscall.SizeofRtMsg
return unix.SizeofRtMsg
}
func DeserializeRtMsg(b []byte) *RtMsg {
return (*RtMsg)(unsafe.Pointer(&b[0:syscall.SizeofRtMsg][0]))
return (*RtMsg)(unsafe.Pointer(&b[0:unix.SizeofRtMsg][0]))
}
func (msg *RtMsg) Serialize() []byte {
return (*(*[syscall.SizeofRtMsg]byte)(unsafe.Pointer(msg)))[:]
return (*(*[unix.SizeofRtMsg]byte)(unsafe.Pointer(msg)))[:]
}
type RtNexthop struct {
syscall.RtNexthop
unix.RtNexthop
Children []NetlinkRequestData
}
func DeserializeRtNexthop(b []byte) *RtNexthop {
return (*RtNexthop)(unsafe.Pointer(&b[0:syscall.SizeofRtNexthop][0]))
return (*RtNexthop)(unsafe.Pointer(&b[0:unix.SizeofRtNexthop][0]))
}
func (msg *RtNexthop) Len() int {
if len(msg.Children) == 0 {
return syscall.SizeofRtNexthop
return unix.SizeofRtNexthop
}
l := 0
for _, child := range msg.Children {
l += rtaAlignOf(child.Len())
}
l += syscall.SizeofRtNexthop
l += unix.SizeofRtNexthop
return rtaAlignOf(l)
}
@ -67,8 +68,8 @@ func (msg *RtNexthop) Serialize() []byte {
length := msg.Len()
msg.RtNexthop.Len = uint16(length)
buf := make([]byte, length)
copy(buf, (*(*[syscall.SizeofRtNexthop]byte)(unsafe.Pointer(msg)))[:])
next := rtaAlignOf(syscall.SizeofRtNexthop)
copy(buf, (*(*[unix.SizeofRtNexthop]byte)(unsafe.Pointer(msg)))[:])
next := rtaAlignOf(unix.SizeofRtNexthop)
if len(msg.Children) > 0 {
for _, child := range msg.Children {
childBuf := child.Serialize()

111
vendor/github.com/vishvananda/netlink/nl/seg6_linux.go generated vendored Normal file
View file

@ -0,0 +1,111 @@
package nl
import (
"errors"
"fmt"
"net"
)
type IPv6SrHdr struct {
nextHdr uint8
hdrLen uint8
routingType uint8
segmentsLeft uint8
firstSegment uint8
flags uint8
reserved uint16
Segments []net.IP
}
func (s1 *IPv6SrHdr) Equal(s2 IPv6SrHdr) bool {
if len(s1.Segments) != len(s2.Segments) {
return false
}
for i := range s1.Segments {
if s1.Segments[i].Equal(s2.Segments[i]) != true {
return false
}
}
return s1.nextHdr == s2.nextHdr &&
s1.hdrLen == s2.hdrLen &&
s1.routingType == s2.routingType &&
s1.segmentsLeft == s2.segmentsLeft &&
s1.firstSegment == s2.firstSegment &&
s1.flags == s2.flags
// reserved doesn't need to be identical.
}
// seg6 encap mode
const (
SEG6_IPTUN_MODE_INLINE = iota
SEG6_IPTUN_MODE_ENCAP
)
// number of nested RTATTR
// from include/uapi/linux/seg6_iptunnel.h
const (
SEG6_IPTUNNEL_UNSPEC = iota
SEG6_IPTUNNEL_SRH
__SEG6_IPTUNNEL_MAX
)
const (
SEG6_IPTUNNEL_MAX = __SEG6_IPTUNNEL_MAX - 1
)
func EncodeSEG6Encap(mode int, segments []net.IP) ([]byte, error) {
nsegs := len(segments) // nsegs: number of segments
if nsegs == 0 {
return nil, errors.New("EncodeSEG6Encap: No Segment in srh")
}
b := make([]byte, 12, 12+len(segments)*16)
native := NativeEndian()
native.PutUint32(b, uint32(mode))
b[4] = 0 // srh.nextHdr (0 when calling netlink)
b[5] = uint8(16 * nsegs >> 3) // srh.hdrLen (in 8-octets unit)
b[6] = IPV6_SRCRT_TYPE_4 // srh.routingType (assigned by IANA)
b[7] = uint8(nsegs - 1) // srh.segmentsLeft
b[8] = uint8(nsegs - 1) // srh.firstSegment
b[9] = 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[10:], 0) // srh.reserved
for _, netIP := range segments {
b = append(b, netIP...) // srh.Segments
}
return b, nil
}
func DecodeSEG6Encap(buf []byte) (int, []net.IP, error) {
native := NativeEndian()
mode := int(native.Uint32(buf))
srh := IPv6SrHdr{
nextHdr: buf[4],
hdrLen: buf[5],
routingType: buf[6],
segmentsLeft: buf[7],
firstSegment: buf[8],
flags: buf[9],
reserved: native.Uint16(buf[10:12]),
}
buf = buf[12:]
if len(buf)%16 != 0 {
err := fmt.Errorf("DecodeSEG6Encap: error parsing Segment List (buf len: %d)\n", len(buf))
return mode, nil, err
}
for len(buf) > 0 {
srh.Segments = append(srh.Segments, net.IP(buf[:16]))
buf = buf[16:]
}
return mode, srh.Segments, nil
}
// Helper functions
func SEG6EncapModeString(mode int) string {
switch mode {
case SEG6_IPTUN_MODE_INLINE:
return "inline"
case SEG6_IPTUN_MODE_ENCAP:
return "encap"
}
return "unknown"
}

View file

@ -65,4 +65,14 @@ const (
LWTUNNEL_ENCAP_IP
LWTUNNEL_ENCAP_ILA
LWTUNNEL_ENCAP_IP6
LWTUNNEL_ENCAP_SEG6
LWTUNNEL_ENCAP_BPF
)
// routing header types
const (
IPV6_SRCRT_STRICT = 0x01 // Deprecated; will be removed
IPV6_SRCRT_TYPE_0 = 0 // Deprecated; will be removed
IPV6_SRCRT_TYPE_2 = 2 // IPv6 type 2 Routing Header
IPV6_SRCRT_TYPE_4 = 4 // Segment Routing with IPv6
)

View file

@ -673,3 +673,38 @@ const (
TCA_FW_MASK
TCA_FW_MAX = TCA_FW_MASK
)
const (
TCA_MATCHALL_UNSPEC = iota
TCA_MATCHALL_CLASSID
TCA_MATCHALL_ACT
TCA_MATCHALL_FLAGS
)
const (
TCA_FQ_UNSPEC = iota
TCA_FQ_PLIMIT // limit of total number of packets in queue
TCA_FQ_FLOW_PLIMIT // limit of packets per flow
TCA_FQ_QUANTUM // RR quantum
TCA_FQ_INITIAL_QUANTUM // RR quantum for new flow
TCA_FQ_RATE_ENABLE // enable/disable rate limiting
TCA_FQ_FLOW_DEFAULT_RATE // obsolete do not use
TCA_FQ_FLOW_MAX_RATE // per flow max rate
TCA_FQ_BUCKETS_LOG // log2(number of buckets)
TCA_FQ_FLOW_REFILL_DELAY // flow credit refill delay in usec
TCA_FQ_ORPHAN_MASK // mask applied to orphaned skb hashes
TCA_FQ_LOW_RATE_THRESHOLD // per packet delay under this rate
)
const (
TCA_FQ_CODEL_UNSPEC = iota
TCA_FQ_CODEL_TARGET
TCA_FQ_CODEL_LIMIT
TCA_FQ_CODEL_INTERVAL
TCA_FQ_CODEL_ECN
TCA_FQ_CODEL_FLOWS
TCA_FQ_CODEL_QUANTUM
TCA_FQ_CODEL_CE_THRESHOLD
TCA_FQ_CODEL_DROP_BATCH_SIZE
TCA_FQ_CODEL_MEMORY_LIMIT
)

View file

@ -5,6 +5,7 @@ import (
"syscall"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
func LinkGetProtinfo(link Link) (Protinfo, error) {
@ -15,10 +16,10 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
base := link.Attrs()
h.ensureIndex(base)
var pi Protinfo
req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP)
msg := nl.NewIfInfomsg(syscall.AF_BRIDGE)
req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, 0)
msgs, err := req.Execute(unix.NETLINK_ROUTE, 0)
if err != nil {
return pi, err
}
@ -33,7 +34,7 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
return pi, err
}
for _, attr := range attrs {
if attr.Attr.Type != syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED {
if attr.Attr.Type != unix.IFLA_PROTINFO|unix.NLA_F_NESTED {
continue
}
infos, err := nl.ParseRouteAttr(attr.Value)

View file

@ -230,3 +230,63 @@ func (qdisc *GenericQdisc) Attrs() *QdiscAttrs {
func (qdisc *GenericQdisc) Type() string {
return qdisc.QdiscType
}
// Fq is a classless packet scheduler meant to be mostly used for locally generated traffic.
type Fq struct {
QdiscAttrs
PacketLimit uint32
FlowPacketLimit uint32
// In bytes
Quantum uint32
InitialQuantum uint32
// called RateEnable under the hood
Pacing uint32
FlowDefaultRate uint32
FlowMaxRate uint32
// called BucketsLog under the hood
Buckets uint32
FlowRefillDelay uint32
LowRateThreshold uint32
}
func NewFq(attrs QdiscAttrs) *Fq {
return &Fq{
QdiscAttrs: attrs,
Pacing: 1,
}
}
func (qdisc *Fq) Attrs() *QdiscAttrs {
return &qdisc.QdiscAttrs
}
func (qdisc *Fq) Type() string {
return "fq"
}
// FQ_Codel (Fair Queuing Controlled Delay) is queuing discipline that combines Fair Queuing with the CoDel AQM scheme.
type FqCodel struct {
QdiscAttrs
Target uint32
Limit uint32
Interval uint32
ECN uint32
Flows uint32
Quantum uint32
// There are some more attributes here, but support for them seems not ubiquitous
}
func NewFqCodel(attrs QdiscAttrs) *FqCodel {
return &FqCodel{
QdiscAttrs: attrs,
ECN: 1,
}
}
func (qdisc *FqCodel) Attrs() *QdiscAttrs {
return &qdisc.QdiscAttrs
}
func (qdisc *FqCodel) Type() string {
return "fq_codel"
}

View file

@ -8,6 +8,7 @@ import (
"syscall"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
// NOTE function is here because it uses other linux functions
@ -84,7 +85,7 @@ func QdiscDel(qdisc Qdisc) error {
// QdiscDel will delete a qdisc from the system.
// Equivalent to: `tc qdisc del $qdisc`
func (h *Handle) QdiscDel(qdisc Qdisc) error {
return h.qdiscModify(syscall.RTM_DELQDISC, 0, qdisc)
return h.qdiscModify(unix.RTM_DELQDISC, 0, qdisc)
}
// QdiscChange will change a qdisc in place
@ -98,7 +99,7 @@ func QdiscChange(qdisc Qdisc) error {
// Equivalent to: `tc qdisc change $qdisc`
// The parent and handle MUST NOT be changed.
func (h *Handle) QdiscChange(qdisc Qdisc) error {
return h.qdiscModify(syscall.RTM_NEWQDISC, 0, qdisc)
return h.qdiscModify(unix.RTM_NEWQDISC, 0, qdisc)
}
// QdiscReplace will replace a qdisc to the system.
@ -113,8 +114,8 @@ func QdiscReplace(qdisc Qdisc) error {
// The handle MUST change.
func (h *Handle) QdiscReplace(qdisc Qdisc) error {
return h.qdiscModify(
syscall.RTM_NEWQDISC,
syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE,
unix.RTM_NEWQDISC,
unix.NLM_F_CREATE|unix.NLM_F_REPLACE,
qdisc)
}
@ -128,13 +129,13 @@ func QdiscAdd(qdisc Qdisc) error {
// Equivalent to: `tc qdisc add $qdisc`
func (h *Handle) QdiscAdd(qdisc Qdisc) error {
return h.qdiscModify(
syscall.RTM_NEWQDISC,
syscall.NLM_F_CREATE|syscall.NLM_F_EXCL,
unix.RTM_NEWQDISC,
unix.NLM_F_CREATE|unix.NLM_F_EXCL,
qdisc)
}
func (h *Handle) qdiscModify(cmd, flags int, qdisc Qdisc) error {
req := h.newNetlinkRequest(cmd, flags|syscall.NLM_F_ACK)
req := h.newNetlinkRequest(cmd, flags|unix.NLM_F_ACK)
base := qdisc.Attrs()
msg := &nl.TcMsg{
Family: nl.FAMILY_ALL,
@ -145,13 +146,13 @@ func (h *Handle) qdiscModify(cmd, flags int, qdisc Qdisc) error {
req.AddData(msg)
// When deleting don't bother building the rest of the netlink payload
if cmd != syscall.RTM_DELQDISC {
if cmd != unix.RTM_DELQDISC {
if err := qdiscPayload(req, qdisc); err != nil {
return err
}
}
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
@ -231,6 +232,48 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
if qdisc.Attrs().Parent != HANDLE_INGRESS {
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))))
if qdisc.Limit > 0 {
nl.NewRtAttrChild(options, 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))))
}
if qdisc.Flows > 0 {
nl.NewRtAttrChild(options, 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))))
}
case *Fq:
nl.NewRtAttrChild(options, 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))))
}
if qdisc.LowRateThreshold > 0 {
nl.NewRtAttrChild(options, 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))))
}
if qdisc.InitialQuantum > 0 {
nl.NewRtAttrChild(options, 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))))
}
if qdisc.FlowPacketLimit > 0 {
nl.NewRtAttrChild(options, 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))))
}
if qdisc.FlowDefaultRate > 0 {
nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_DEFAULT_RATE, nl.Uint32Attr((uint32(qdisc.FlowDefaultRate))))
}
}
req.AddData(options)
@ -248,7 +291,7 @@ func QdiscList(link Link) ([]Qdisc, error) {
// Equivalent to: `tc qdisc show`.
// The list can be filtered by link.
func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
req := h.newNetlinkRequest(syscall.RTM_GETQDISC, syscall.NLM_F_DUMP)
req := h.newNetlinkRequest(unix.RTM_GETQDISC, unix.NLM_F_DUMP)
index := int32(0)
if link != nil {
base := link.Attrs()
@ -261,7 +304,7 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
}
req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWQDISC)
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWQDISC)
if err != nil {
return nil, err
}
@ -303,6 +346,10 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
qdisc = &Ingress{}
case "htb":
qdisc = &Htb{}
case "fq":
qdisc = &Fq{}
case "fq_codel":
qdisc = &FqCodel{}
case "netem":
qdisc = &Netem{}
default:
@ -336,6 +383,22 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
if err := parseHtbData(qdisc, data); err != nil {
return nil, err
}
case "fq":
data, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
return nil, err
}
if err := parseFqData(qdisc, data); err != nil {
return nil, err
}
case "fq_codel":
data, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
return nil, err
}
if err := parseFqCodelData(qdisc, data); err != nil {
return nil, err
}
case "netem":
if err := parseNetemData(qdisc, attr.Value); err != nil {
return nil, err
@ -388,6 +451,61 @@ func parseHtbData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
return nil
}
func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
native = nl.NativeEndian()
fqCodel := qdisc.(*FqCodel)
for _, datum := range data {
switch datum.Attr.Type {
case nl.TCA_FQ_CODEL_TARGET:
fqCodel.Target = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_LIMIT:
fqCodel.Limit = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_INTERVAL:
fqCodel.Interval = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_ECN:
fqCodel.ECN = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_FLOWS:
fqCodel.Flows = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_QUANTUM:
fqCodel.Quantum = native.Uint32(datum.Value)
}
}
return nil
}
func parseFqData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
native = nl.NativeEndian()
fq := qdisc.(*Fq)
for _, datum := range data {
switch datum.Attr.Type {
case nl.TCA_FQ_BUCKETS_LOG:
fq.Buckets = native.Uint32(datum.Value)
case nl.TCA_FQ_LOW_RATE_THRESHOLD:
fq.LowRateThreshold = native.Uint32(datum.Value)
case nl.TCA_FQ_QUANTUM:
fq.Quantum = native.Uint32(datum.Value)
case nl.TCA_FQ_RATE_ENABLE:
fq.Pacing = native.Uint32(datum.Value)
case nl.TCA_FQ_INITIAL_QUANTUM:
fq.InitialQuantum = native.Uint32(datum.Value)
case nl.TCA_FQ_ORPHAN_MASK:
// TODO
case nl.TCA_FQ_FLOW_REFILL_DELAY:
fq.FlowRefillDelay = native.Uint32(datum.Value)
case nl.TCA_FQ_FLOW_PLIMIT:
fq.FlowPacketLimit = native.Uint32(datum.Value)
case nl.TCA_FQ_PLIMIT:
fq.PacketLimit = native.Uint32(datum.Value)
case nl.TCA_FQ_FLOW_MAX_RATE:
fq.FlowMaxRate = native.Uint32(datum.Value)
case nl.TCA_FQ_FLOW_DEFAULT_RATE:
fq.FlowDefaultRate = native.Uint32(datum.Value)
}
}
return nil
}
func parseNetemData(qdisc Qdisc, value []byte) error {
netem := qdisc.(*Netem)
opt := nl.DeserializeTcNetemQopt(value)

View file

@ -45,6 +45,8 @@ type Route struct {
MPLSDst *int
NewDst Destination
Encap Encap
MTU int
AdvMSS int
}
func (r Route) String() string {

View file

@ -8,16 +8,17 @@ import (
"github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
)
// RtAttr is shared so it is in netlink_linux.go
const (
SCOPE_UNIVERSE Scope = syscall.RT_SCOPE_UNIVERSE
SCOPE_SITE Scope = syscall.RT_SCOPE_SITE
SCOPE_LINK Scope = syscall.RT_SCOPE_LINK
SCOPE_HOST Scope = syscall.RT_SCOPE_HOST
SCOPE_NOWHERE Scope = syscall.RT_SCOPE_NOWHERE
SCOPE_UNIVERSE Scope = unix.RT_SCOPE_UNIVERSE
SCOPE_SITE Scope = unix.RT_SCOPE_SITE
SCOPE_LINK Scope = unix.RT_SCOPE_LINK
SCOPE_HOST Scope = unix.RT_SCOPE_HOST
SCOPE_NOWHERE Scope = unix.RT_SCOPE_NOWHERE
)
const (
@ -34,8 +35,8 @@ const (
)
const (
FLAG_ONLINK NextHopFlag = syscall.RTNH_F_ONLINK
FLAG_PERVASIVE NextHopFlag = syscall.RTNH_F_PERVASIVE
FLAG_ONLINK NextHopFlag = unix.RTNH_F_ONLINK
FLAG_PERVASIVE NextHopFlag = unix.RTNH_F_PERVASIVE
)
var testFlags = []flagString{
@ -124,17 +125,17 @@ func (e *MPLSEncap) Type() int {
func (e *MPLSEncap) Decode(buf []byte) error {
if len(buf) < 4 {
return fmt.Errorf("Lack of bytes")
return fmt.Errorf("lack of bytes")
}
native := nl.NativeEndian()
l := native.Uint16(buf)
if len(buf) < int(l) {
return fmt.Errorf("Lack of bytes")
return fmt.Errorf("lack of bytes")
}
buf = buf[:l]
typ := native.Uint16(buf[2:])
if typ != nl.MPLS_IPTUNNEL_DST {
return fmt.Errorf("Unknown MPLS Encap Type: %d", typ)
return fmt.Errorf("unknown MPLS Encap Type: %d", typ)
}
e.Labels = nl.DecodeMPLSStack(buf[4:])
return nil
@ -185,6 +186,79 @@ func (e *MPLSEncap) Equal(x Encap) bool {
return true
}
// SEG6 definitions
type SEG6Encap struct {
Mode int
Segments []net.IP
}
func (e *SEG6Encap) Type() int {
return nl.LWTUNNEL_ENCAP_SEG6
}
func (e *SEG6Encap) Decode(buf []byte) error {
if len(buf) < 4 {
return fmt.Errorf("lack of bytes")
}
native := nl.NativeEndian()
// Get Length(l) & Type(typ) : 2 + 2 bytes
l := native.Uint16(buf)
if len(buf) < int(l) {
return fmt.Errorf("lack of bytes")
}
buf = buf[:l] // make sure buf size upper limit is Length
typ := native.Uint16(buf[2:])
if typ != nl.SEG6_IPTUNNEL_SRH {
return fmt.Errorf("unknown SEG6 Type: %d", typ)
}
var err error
e.Mode, e.Segments, err = nl.DecodeSEG6Encap(buf[4:])
return err
}
func (e *SEG6Encap) Encode() ([]byte, error) {
s, err := nl.EncodeSEG6Encap(e.Mode, e.Segments)
native := nl.NativeEndian()
hdr := make([]byte, 4)
native.PutUint16(hdr, uint16(len(s)+4))
native.PutUint16(hdr[2:], nl.SEG6_IPTUNNEL_SRH)
return append(hdr, s...), err
}
func (e *SEG6Encap) String() string {
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]))
}
str := fmt.Sprintf("mode %s segs %d [ %s ]", nl.SEG6EncapModeString(e.Mode),
len(e.Segments), strings.Join(segs, " "))
return str
}
func (e *SEG6Encap) Equal(x Encap) bool {
o, ok := x.(*SEG6Encap)
if !ok {
return false
}
if e == o {
return true
}
if e == nil || o == nil {
return false
}
if e.Mode != o.Mode {
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
}
}
return true
}
// RouteAdd will add a route to the system.
// Equivalent to: `ip route add $route`
func RouteAdd(route *Route) error {
@ -194,8 +268,8 @@ func RouteAdd(route *Route) error {
// RouteAdd will add a route to the system.
// Equivalent to: `ip route add $route`
func (h *Handle) RouteAdd(route *Route) error {
flags := syscall.NLM_F_CREATE | syscall.NLM_F_EXCL | syscall.NLM_F_ACK
req := h.newNetlinkRequest(syscall.RTM_NEWROUTE, flags)
flags := unix.NLM_F_CREATE | unix.NLM_F_EXCL | unix.NLM_F_ACK
req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags)
return h.routeHandle(route, req, nl.NewRtMsg())
}
@ -208,8 +282,8 @@ func RouteReplace(route *Route) error {
// RouteReplace will add a route to the system.
// Equivalent to: `ip route replace $route`
func (h *Handle) RouteReplace(route *Route) error {
flags := syscall.NLM_F_CREATE | syscall.NLM_F_REPLACE | syscall.NLM_F_ACK
req := h.newNetlinkRequest(syscall.RTM_NEWROUTE, flags)
flags := unix.NLM_F_CREATE | unix.NLM_F_REPLACE | unix.NLM_F_ACK
req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags)
return h.routeHandle(route, req, nl.NewRtMsg())
}
@ -222,7 +296,7 @@ func RouteDel(route *Route) error {
// RouteDel will delete a route from the system.
// Equivalent to: `ip route del $route`
func (h *Handle) RouteDel(route *Route) error {
req := h.newNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK)
req := h.newNetlinkRequest(unix.RTM_DELROUTE, unix.NLM_F_ACK)
return h.routeHandle(route, req, nl.NewRtDelMsg())
}
@ -245,12 +319,12 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
} else {
dstData = route.Dst.IP.To16()
}
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, dstData))
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, dstData))
} else if route.MPLSDst != nil {
family = nl.FAMILY_MPLS
msg.Dst_len = uint8(20)
msg.Type = syscall.RTN_UNICAST
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, nl.EncodeMPLSStack(*route.MPLSDst)))
msg.Type = unix.RTN_UNICAST
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, nl.EncodeMPLSStack(*route.MPLSDst)))
}
if route.NewDst != nil {
@ -288,7 +362,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
srcData = route.Src.To16()
}
// The commonly used src ip for routes is actually PREFSRC
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PREFSRC, srcData))
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_PREFSRC, srcData))
}
if route.Gw != nil {
@ -303,14 +377,14 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
} else {
gwData = route.Gw.To16()
}
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_GATEWAY, gwData))
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_GATEWAY, gwData))
}
if len(route.MultiPath) > 0 {
buf := []byte{}
for _, nh := range route.MultiPath {
rtnh := &nl.RtNexthop{
RtNexthop: syscall.RtNexthop{
RtNexthop: unix.RtNexthop{
Hops: uint8(nh.Hops),
Ifindex: int32(nh.LinkIndex),
Flags: uint8(nh.Flags),
@ -323,9 +397,9 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
return fmt.Errorf("gateway, source, and destination ip are not the same IP family")
}
if gwFamily == FAMILY_V4 {
children = append(children, nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To4())))
children = append(children, nl.NewRtAttr(unix.RTA_GATEWAY, []byte(nh.Gw.To4())))
} else {
children = append(children, nl.NewRtAttr(syscall.RTA_GATEWAY, []byte(nh.Gw.To16())))
children = append(children, nl.NewRtAttr(unix.RTA_GATEWAY, []byte(nh.Gw.To16())))
}
}
if nh.NewDst != nil {
@ -351,15 +425,15 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
rtnh.Children = children
buf = append(buf, rtnh.Serialize()...)
}
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_MULTIPATH, buf))
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_MULTIPATH, buf))
}
if route.Table > 0 {
if route.Table >= 256 {
msg.Table = syscall.RT_TABLE_UNSPEC
msg.Table = unix.RT_TABLE_UNSPEC
b := make([]byte, 4)
native.PutUint32(b, uint32(route.Table))
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_TABLE, b))
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_TABLE, b))
} else {
msg.Table = uint8(route.Table)
}
@ -368,7 +442,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
if route.Priority > 0 {
b := make([]byte, 4)
native.PutUint32(b, uint32(route.Priority))
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PRIORITY, b))
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_PRIORITY, b))
}
if route.Tos > 0 {
msg.Tos = uint8(route.Tos)
@ -380,6 +454,25 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
msg.Type = uint8(route.Type)
}
var metrics []*nl.RtAttr
// TODO: support other rta_metric values
if route.MTU > 0 {
b := nl.Uint32Attr(uint32(route.MTU))
metrics = append(metrics, nl.NewRtAttr(unix.RTAX_MTU, b))
}
if route.AdvMSS > 0 {
b := nl.Uint32Attr(uint32(route.AdvMSS))
metrics = append(metrics, nl.NewRtAttr(unix.RTAX_ADVMSS, b))
}
if metrics != nil {
attr := nl.NewRtAttr(unix.RTA_METRICS, nil)
for _, metric := range metrics {
attr.AddChild(metric)
}
rtAttrs = append(rtAttrs, attr)
}
msg.Flags = uint32(route.Flags)
msg.Scope = uint8(route.Scope)
msg.Family = uint8(family)
@ -394,9 +487,9 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
)
native.PutUint32(b, uint32(route.LinkIndex))
req.AddData(nl.NewRtAttr(syscall.RTA_OIF, b))
req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
@ -429,11 +522,11 @@ func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, e
// RouteListFiltered gets a list of routes in the system filtered with specified rules.
// All rules must be defined in RouteFilter struct
func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
req := h.newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP)
req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_DUMP)
infmsg := nl.NewIfInfomsg(family)
req.AddData(infmsg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE)
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE)
if err != nil {
return nil, err
}
@ -441,11 +534,11 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
var res []Route
for _, m := range msgs {
msg := nl.DeserializeRtMsg(m)
if msg.Flags&syscall.RTM_F_CLONED != 0 {
if msg.Flags&unix.RTM_F_CLONED != 0 {
// Ignore cloned routes
continue
}
if msg.Table != syscall.RT_TABLE_MAIN {
if msg.Table != unix.RT_TABLE_MAIN {
if filter == nil || filter != nil && filterMask&RT_FILTER_TABLE == 0 {
// Ignore non-main tables
continue
@ -457,7 +550,7 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
}
if filter != nil {
switch {
case filterMask&RT_FILTER_TABLE != 0 && filter.Table != syscall.RT_TABLE_UNSPEC && route.Table != filter.Table:
case filterMask&RT_FILTER_TABLE != 0 && filter.Table != unix.RT_TABLE_UNSPEC && route.Table != filter.Table:
continue
case filterMask&RT_FILTER_PROTOCOL != 0 && route.Protocol != filter.Protocol:
continue
@ -508,11 +601,11 @@ func deserializeRoute(m []byte) (Route, error) {
var encap, encapType syscall.NetlinkRouteAttr
for _, attr := range attrs {
switch attr.Attr.Type {
case syscall.RTA_GATEWAY:
case unix.RTA_GATEWAY:
route.Gw = net.IP(attr.Value)
case syscall.RTA_PREFSRC:
case unix.RTA_PREFSRC:
route.Src = net.IP(attr.Value)
case syscall.RTA_DST:
case unix.RTA_DST:
if msg.Family == nl.FAMILY_MPLS {
stack := nl.DecodeMPLSStack(attr.Value)
if len(stack) == 0 || len(stack) > 1 {
@ -525,36 +618,36 @@ func deserializeRoute(m []byte) (Route, error) {
Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)),
}
}
case syscall.RTA_OIF:
case unix.RTA_OIF:
route.LinkIndex = int(native.Uint32(attr.Value[0:4]))
case syscall.RTA_IIF:
case unix.RTA_IIF:
route.ILinkIndex = int(native.Uint32(attr.Value[0:4]))
case syscall.RTA_PRIORITY:
case unix.RTA_PRIORITY:
route.Priority = int(native.Uint32(attr.Value[0:4]))
case syscall.RTA_TABLE:
case unix.RTA_TABLE:
route.Table = int(native.Uint32(attr.Value[0:4]))
case syscall.RTA_MULTIPATH:
case unix.RTA_MULTIPATH:
parseRtNexthop := func(value []byte) (*NexthopInfo, []byte, error) {
if len(value) < syscall.SizeofRtNexthop {
return nil, nil, fmt.Errorf("Lack of bytes")
if len(value) < unix.SizeofRtNexthop {
return nil, nil, fmt.Errorf("lack of bytes")
}
nh := nl.DeserializeRtNexthop(value)
if len(value) < int(nh.RtNexthop.Len) {
return nil, nil, fmt.Errorf("Lack of bytes")
return nil, nil, fmt.Errorf("lack of bytes")
}
info := &NexthopInfo{
LinkIndex: int(nh.RtNexthop.Ifindex),
Hops: int(nh.RtNexthop.Hops),
Flags: int(nh.RtNexthop.Flags),
}
attrs, err := nl.ParseRouteAttr(value[syscall.SizeofRtNexthop:int(nh.RtNexthop.Len)])
attrs, err := nl.ParseRouteAttr(value[unix.SizeofRtNexthop:int(nh.RtNexthop.Len)])
if err != nil {
return nil, nil, err
}
var encap, encapType syscall.NetlinkRouteAttr
for _, attr := range attrs {
switch attr.Attr.Type {
case syscall.RTA_GATEWAY:
case unix.RTA_GATEWAY:
info.Gw = net.IP(attr.Value)
case nl.RTA_NEWDST:
var d Destination
@ -611,6 +704,19 @@ func deserializeRoute(m []byte) (Route, error) {
encapType = attr
case nl.RTA_ENCAP:
encap = attr
case unix.RTA_METRICS:
metrics, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
return route, err
}
for _, metric := range metrics {
switch metric.Attr.Type {
case unix.RTAX_MTU:
route.MTU = int(native.Uint32(metric.Value[0:4]))
case unix.RTAX_ADVMSS:
route.AdvMSS = int(native.Uint32(metric.Value[0:4]))
}
}
}
}
@ -623,6 +729,11 @@ func deserializeRoute(m []byte) (Route, error) {
if err := e.Decode(encap.Value); err != nil {
return route, err
}
case nl.LWTUNNEL_ENCAP_SEG6:
e = &SEG6Encap{}
if err := e.Decode(encap.Value); err != nil {
return route, err
}
}
route.Encap = e
}
@ -639,7 +750,7 @@ func RouteGet(destination net.IP) ([]Route, error) {
// RouteGet gets a route to a specific destination from the host system.
// Equivalent to: 'ip route get'.
func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
req := h.newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_REQUEST)
req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_REQUEST)
family := nl.GetIPFamily(destination)
var destinationData []byte
var bitlen uint8
@ -655,10 +766,10 @@ func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
msg.Dst_len = bitlen
req.AddData(msg)
rtaDst := nl.NewRtAttr(syscall.RTA_DST, destinationData)
rtaDst := nl.NewRtAttr(unix.RTA_DST, destinationData)
req.AddData(rtaDst)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE)
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE)
if err != nil {
return nil, err
}
@ -678,13 +789,13 @@ func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
// RouteSubscribe takes a chan down which notifications will be sent
// when routes are added or deleted. Close the 'done' chan to stop subscription.
func RouteSubscribe(ch chan<- RouteUpdate, done <-chan struct{}) error {
return routeSubscribeAt(netns.None(), netns.None(), ch, done, nil)
return routeSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
}
// RouteSubscribeAt works like RouteSubscribe plus it allows the caller
// to choose the network namespace in which to subscribe (ns).
func RouteSubscribeAt(ns netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}) error {
return routeSubscribeAt(ns, netns.None(), ch, done, nil)
return routeSubscribeAt(ns, netns.None(), ch, done, nil, false)
}
// RouteSubscribeOptions contains a set of options to use with
@ -692,6 +803,7 @@ func RouteSubscribeAt(ns netns.NsHandle, ch chan<- RouteUpdate, done <-chan stru
type RouteSubscribeOptions struct {
Namespace *netns.NsHandle
ErrorCallback func(error)
ListExisting bool
}
// RouteSubscribeWithOptions work like RouteSubscribe but enable to
@ -702,11 +814,11 @@ func RouteSubscribeWithOptions(ch chan<- RouteUpdate, done <-chan struct{}, opti
none := netns.None()
options.Namespace = &none
}
return routeSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback)
return routeSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
}
func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}, cberr func(error)) error {
s, err := nl.SubscribeAt(newNs, curNs, syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_ROUTE, syscall.RTNLGRP_IPV6_ROUTE)
func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_ROUTE, unix.RTNLGRP_IPV6_ROUTE)
if err != nil {
return err
}
@ -716,6 +828,15 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
s.Close()
}()
}
if listExisting {
req := pkgHandle.newNetlinkRequest(unix.RTM_GETROUTE,
unix.NLM_F_DUMP)
infmsg := nl.NewIfInfomsg(unix.AF_UNSPEC)
req.AddData(infmsg)
if err := s.Send(req); err != nil {
return err
}
}
go func() {
defer close(ch)
for {
@ -727,6 +848,20 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
return
}
for _, m := range msgs {
if m.Header.Type == unix.NLMSG_DONE {
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
}
route, err := deserializeRoute(m.Data)
if err != nil {
if cberr != nil {

View file

@ -21,6 +21,7 @@ type Rule struct {
OifName string
SuppressIfgroup int
SuppressPrefixlen int
Invert bool
}
func (r Rule) String() string {

View file

@ -3,11 +3,13 @@ package netlink
import (
"fmt"
"net"
"syscall"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
const FibRuleInvert = 0x2
// RuleAdd adds a rule to the system.
// Equivalent to: ip rule add
func RuleAdd(rule *Rule) error {
@ -17,7 +19,7 @@ func RuleAdd(rule *Rule) error {
// RuleAdd adds a rule to the system.
// Equivalent to: ip rule add
func (h *Handle) RuleAdd(rule *Rule) error {
req := h.newNetlinkRequest(syscall.RTM_NEWRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
req := h.newNetlinkRequest(unix.RTM_NEWRULE, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
return ruleHandle(rule, req)
}
@ -30,18 +32,31 @@ func RuleDel(rule *Rule) error {
// RuleDel deletes a rule from the system.
// Equivalent to: ip rule del
func (h *Handle) RuleDel(rule *Rule) error {
req := h.newNetlinkRequest(syscall.RTM_DELRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
req := h.newNetlinkRequest(unix.RTM_DELRULE, unix.NLM_F_ACK)
return ruleHandle(rule, req)
}
func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
msg := nl.NewRtMsg()
msg.Family = syscall.AF_INET
msg.Family = unix.AF_INET
msg.Protocol = unix.RTPROT_BOOT
msg.Scope = unix.RT_SCOPE_UNIVERSE
msg.Table = unix.RT_TABLE_UNSPEC
msg.Type = unix.RTN_UNSPEC
if req.NlMsghdr.Flags&unix.NLM_F_CREATE > 0 {
msg.Type = unix.RTN_UNICAST
}
if rule.Invert {
msg.Flags |= FibRuleInvert
}
if rule.Family != 0 {
msg.Family = uint8(rule.Family)
}
var dstFamily uint8
if rule.Table >= 0 && rule.Table < 256 {
msg.Table = uint8(rule.Table)
}
var dstFamily uint8
var rtAttrs []*nl.RtAttr
if rule.Dst != nil && rule.Dst.IP != nil {
dstLen, _ := rule.Dst.Mask.Size()
@ -49,12 +64,12 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
msg.Family = uint8(nl.GetIPFamily(rule.Dst.IP))
dstFamily = msg.Family
var dstData []byte
if msg.Family == syscall.AF_INET {
if msg.Family == unix.AF_INET {
dstData = rule.Dst.IP.To4()
} else {
dstData = rule.Dst.IP.To16()
}
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, dstData))
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, dstData))
}
if rule.Src != nil && rule.Src.IP != nil {
@ -65,19 +80,12 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
srcLen, _ := rule.Src.Mask.Size()
msg.Src_len = uint8(srcLen)
var srcData []byte
if msg.Family == syscall.AF_INET {
if msg.Family == unix.AF_INET {
srcData = rule.Src.IP.To4()
} else {
srcData = rule.Src.IP.To16()
}
rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_SRC, srcData))
}
if rule.Table >= 0 {
msg.Table = uint8(rule.Table)
if rule.Table >= 256 {
msg.Table = syscall.RT_TABLE_UNSPEC
}
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_SRC, srcData))
}
req.AddData(msg)
@ -142,7 +150,7 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
req.AddData(nl.NewRtAttr(nl.FRA_GOTO, b))
}
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
@ -155,11 +163,11 @@ func RuleList(family int) ([]Rule, error) {
// RuleList lists rules in the system.
// Equivalent to: ip rule list
func (h *Handle) RuleList(family int) ([]Rule, error) {
req := h.newNetlinkRequest(syscall.RTM_GETRULE, syscall.NLM_F_DUMP|syscall.NLM_F_REQUEST)
req := h.newNetlinkRequest(unix.RTM_GETRULE, unix.NLM_F_DUMP|unix.NLM_F_REQUEST)
msg := nl.NewIfInfomsg(family)
req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWRULE)
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWRULE)
if err != nil {
return nil, err
}
@ -175,9 +183,11 @@ func (h *Handle) RuleList(family int) ([]Rule, error) {
rule := NewRule()
rule.Invert = msg.Flags&FibRuleInvert > 0
for j := range attrs {
switch attrs[j].Attr.Type {
case syscall.RTA_TABLE:
case unix.RTA_TABLE:
rule.Table = int(native.Uint32(attrs[j].Value[0:4]))
case nl.FRA_SRC:
rule.Src = &net.IPNet{

View file

@ -4,9 +4,9 @@ import (
"errors"
"fmt"
"net"
"syscall"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
const (
@ -123,15 +123,15 @@ func SocketGet(local, remote net.Addr) (*Socket, error) {
return nil, ErrNotImplemented
}
s, err := nl.Subscribe(syscall.NETLINK_INET_DIAG)
s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
if err != nil {
return nil, err
}
defer s.Close()
req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, 0)
req.AddData(&socketRequest{
Family: syscall.AF_INET,
Protocol: syscall.IPPROTO_TCP,
Family: unix.AF_INET,
Protocol: unix.IPPROTO_TCP,
ID: SocketID{
SourcePort: uint16(localTCP.Port),
DestinationPort: uint16(remoteTCP.Port),

View file

@ -2,19 +2,20 @@ package netlink
import (
"fmt"
"syscall"
"golang.org/x/sys/unix"
)
// Proto is an enum representing an ipsec protocol.
type Proto uint8
const (
XFRM_PROTO_ROUTE2 Proto = syscall.IPPROTO_ROUTING
XFRM_PROTO_ESP Proto = syscall.IPPROTO_ESP
XFRM_PROTO_AH Proto = syscall.IPPROTO_AH
XFRM_PROTO_HAO Proto = syscall.IPPROTO_DSTOPTS
XFRM_PROTO_ROUTE2 Proto = unix.IPPROTO_ROUTING
XFRM_PROTO_ESP Proto = unix.IPPROTO_ESP
XFRM_PROTO_AH Proto = unix.IPPROTO_AH
XFRM_PROTO_HAO Proto = unix.IPPROTO_DSTOPTS
XFRM_PROTO_COMP Proto = 0x6c // NOTE not defined on darwin
XFRM_PROTO_IPSEC_ANY Proto = syscall.IPPROTO_RAW
XFRM_PROTO_IPSEC_ANY Proto = unix.IPPROTO_RAW
)
func (p Proto) String() string {

View file

@ -2,11 +2,10 @@ package netlink
import (
"fmt"
"syscall"
"github.com/vishvananda/netns"
"github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
)
type XfrmMsg interface {
@ -39,7 +38,7 @@ func XfrmMonitor(ch chan<- XfrmMsg, done <-chan struct{}, errorChan chan<- error
if err != nil {
return nil
}
s, err := nl.SubscribeAt(netns.None(), netns.None(), syscall.NETLINK_XFRM, groups...)
s, err := nl.SubscribeAt(netns.None(), netns.None(), unix.NETLINK_XFRM, groups...)
if err != nil {
return err
}

View file

@ -1,9 +1,8 @@
package netlink
import (
"syscall"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) {
@ -55,7 +54,7 @@ func (h *Handle) XfrmPolicyUpdate(policy *XfrmPolicy) error {
}
func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
req := h.newNetlinkRequest(nlProto, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
msg := &nl.XfrmUserpolicyInfo{}
selFromPolicy(&msg.Sel, policy)
@ -91,7 +90,7 @@ func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
req.AddData(out)
}
_, err := req.Execute(syscall.NETLINK_XFRM, 0)
_, err := req.Execute(unix.NETLINK_XFRM, 0)
return err
}
@ -121,12 +120,12 @@ func XfrmPolicyList(family int) ([]XfrmPolicy, error) {
// Equivalent to: `ip xfrm policy show`.
// The list can be filtered by ip family.
func (h *Handle) XfrmPolicyList(family int) ([]XfrmPolicy, error) {
req := h.newNetlinkRequest(nl.XFRM_MSG_GETPOLICY, syscall.NLM_F_DUMP)
req := h.newNetlinkRequest(nl.XFRM_MSG_GETPOLICY, unix.NLM_F_DUMP)
msg := nl.NewIfInfomsg(family)
req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY)
msgs, err := req.Execute(unix.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY)
if err != nil {
return nil, err
}
@ -165,13 +164,13 @@ func XfrmPolicyFlush() error {
// XfrmPolicyFlush will flush the policies on the system.
// Equivalent to: `ip xfrm policy flush`
func (h *Handle) XfrmPolicyFlush() error {
req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHPOLICY, syscall.NLM_F_ACK)
_, err := req.Execute(syscall.NETLINK_XFRM, 0)
req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHPOLICY, unix.NLM_F_ACK)
_, err := req.Execute(unix.NETLINK_XFRM, 0)
return err
}
func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPolicy, error) {
req := h.newNetlinkRequest(nlProto, syscall.NLM_F_ACK)
req := h.newNetlinkRequest(nlProto, unix.NLM_F_ACK)
msg := &nl.XfrmUserpolicyId{}
selFromPolicy(&msg.Sel, policy)
@ -189,7 +188,7 @@ func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPo
resType = 0
}
msgs, err := req.Execute(syscall.NETLINK_XFRM, uint16(resType))
msgs, err := req.Execute(unix.NETLINK_XFRM, uint16(resType))
if err != nil {
return nil, err
}

View file

@ -3,6 +3,7 @@ package netlink
import (
"fmt"
"net"
"time"
)
// XfrmStateAlgo represents the algorithm to use for the ipsec encryption.
@ -67,6 +68,19 @@ type XfrmStateLimits struct {
TimeUseHard uint64
}
// XfrmStateStats represents the current number of bytes/packets
// processed by this State, the State's installation and first use
// time and the replay window counters.
type XfrmStateStats struct {
ReplayWindow uint32
Replay uint32
Failed uint32
Bytes uint64
Packets uint64
AddTime uint64
UseTime uint64
}
// XfrmState represents the state of an ipsec policy. It optionally
// contains an XfrmStateAlgo for encryption and one for authentication.
type XfrmState struct {
@ -78,6 +92,7 @@ type XfrmState struct {
Reqid int
ReplayWindow int
Limits XfrmStateLimits
Statistics XfrmStateStats
Mark *XfrmMark
Auth *XfrmStateAlgo
Crypt *XfrmStateAlgo
@ -94,10 +109,16 @@ func (sa XfrmState) Print(stats bool) string {
if !stats {
return sa.String()
}
return fmt.Sprintf("%s, ByteSoft: %s, ByteHard: %s, PacketSoft: %s, PacketHard: %s, TimeSoft: %d, TimeHard: %d, TimeUseSoft: %d, TimeUseHard: %d",
at := time.Unix(int64(sa.Statistics.AddTime), 0).Format(time.UnixDate)
ut := "-"
if sa.Statistics.UseTime > 0 {
ut = time.Unix(int64(sa.Statistics.UseTime), 0).Format(time.UnixDate)
}
return fmt.Sprintf("%s, ByteSoft: %s, ByteHard: %s, PacketSoft: %s, PacketHard: %s, TimeSoft: %d, TimeHard: %d, TimeUseSoft: %d, TimeUseHard: %d, Bytes: %d, Packets: %d, "+
"AddTime: %s, UseTime: %s, ReplayWindow: %d, Replay: %d, Failed: %d",
sa.String(), printLimit(sa.Limits.ByteSoft), printLimit(sa.Limits.ByteHard), printLimit(sa.Limits.PacketSoft), printLimit(sa.Limits.PacketHard),
sa.Limits.TimeSoft, sa.Limits.TimeHard, sa.Limits.TimeUseSoft, sa.Limits.TimeUseHard)
sa.Limits.TimeSoft, sa.Limits.TimeHard, sa.Limits.TimeUseSoft, sa.Limits.TimeUseHard, sa.Statistics.Bytes, sa.Statistics.Packets, at, ut,
sa.Statistics.ReplayWindow, sa.Statistics.Replay, sa.Statistics.Failed)
}
func printLimit(lmt uint64) string {

View file

@ -2,10 +2,10 @@ package netlink
import (
"fmt"
"syscall"
"unsafe"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
func writeStateAlgo(a *XfrmStateAlgo) []byte {
@ -69,8 +69,10 @@ func writeReplayEsn(replayWindow int) []byte {
ReplayWindow: uint32(replayWindow),
}
// taken from iproute2/ip/xfrm_state.c:
replayEsn.BmpLen = uint32((replayWindow + (4 * 8) - 1) / (4 * 8))
// Linux stores the bitmap to identify the already received sequence packets in blocks of uint32 elements.
// Therefore bitmap length is the minimum number of uint32 elements needed. The following is a ceiling operation.
bytesPerElem := int(unsafe.Sizeof(replayEsn.BmpLen)) // Any uint32 variable is good for this
replayEsn.BmpLen = uint32((replayWindow + (bytesPerElem * 8) - 1) / (bytesPerElem * 8))
return replayEsn.Serialize()
}
@ -111,7 +113,7 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
if state.Spi == 0 {
return fmt.Errorf("Spi must be set when adding xfrm state.")
}
req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
req := h.newNetlinkRequest(nlProto, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
msg := xfrmUsersaInfoFromXfrmState(state)
@ -157,13 +159,13 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
req.AddData(out)
}
_, err := req.Execute(syscall.NETLINK_XFRM, 0)
_, err := req.Execute(unix.NETLINK_XFRM, 0)
return err
}
func (h *Handle) xfrmStateAllocSpi(state *XfrmState) (*XfrmState, error) {
req := h.newNetlinkRequest(nl.XFRM_MSG_ALLOCSPI,
syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
msg := &nl.XfrmUserSpiInfo{}
msg.XfrmUsersaInfo = *(xfrmUsersaInfoFromXfrmState(state))
@ -177,7 +179,7 @@ func (h *Handle) xfrmStateAllocSpi(state *XfrmState) (*XfrmState, error) {
req.AddData(out)
}
msgs, err := req.Execute(syscall.NETLINK_XFRM, 0)
msgs, err := req.Execute(unix.NETLINK_XFRM, 0)
if err != nil {
return nil, err
}
@ -216,9 +218,9 @@ func XfrmStateList(family int) ([]XfrmState, error) {
// Equivalent to: `ip xfrm state show`.
// The list can be filtered by ip family.
func (h *Handle) XfrmStateList(family int) ([]XfrmState, error) {
req := h.newNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP)
req := h.newNetlinkRequest(nl.XFRM_MSG_GETSA, unix.NLM_F_DUMP)
msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
msgs, err := req.Execute(unix.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
if err != nil {
return nil, err
}
@ -255,7 +257,7 @@ func (h *Handle) XfrmStateGet(state *XfrmState) (*XfrmState, error) {
}
func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState, error) {
req := h.newNetlinkRequest(nlProto, syscall.NLM_F_ACK)
req := h.newNetlinkRequest(nlProto, unix.NLM_F_ACK)
msg := &nl.XfrmUsersaId{}
msg.Family = uint16(nl.GetIPFamily(state.Dst))
@ -278,7 +280,7 @@ func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState
resType = 0
}
msgs, err := req.Execute(syscall.NETLINK_XFRM, uint16(resType))
msgs, err := req.Execute(unix.NETLINK_XFRM, uint16(resType))
if err != nil {
return nil, err
}
@ -308,6 +310,7 @@ func xfrmStateFromXfrmUsersaInfo(msg *nl.XfrmUsersaInfo) *XfrmState {
state.Reqid = int(msg.Reqid)
state.ReplayWindow = int(msg.ReplayWindow)
lftToLimits(&msg.Lft, &state.Limits)
curToStats(&msg.Curlft, &msg.Stats, &state.Statistics)
return &state
}
@ -386,11 +389,11 @@ func XfrmStateFlush(proto Proto) error {
// proto = 0 means any transformation protocols
// Equivalent to: `ip xfrm state flush [ proto XFRM-PROTO ]`
func (h *Handle) XfrmStateFlush(proto Proto) error {
req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHSA, syscall.NLM_F_ACK)
req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHSA, unix.NLM_F_ACK)
req.AddData(&nl.XfrmUsersaFlush{Proto: uint8(proto)})
_, err := req.Execute(syscall.NETLINK_XFRM, 0)
_, err := req.Execute(unix.NETLINK_XFRM, 0)
if err != nil {
return err
}
@ -429,6 +432,16 @@ func lftToLimits(lft *nl.XfrmLifetimeCfg, lmts *XfrmStateLimits) {
*lmts = *(*XfrmStateLimits)(unsafe.Pointer(lft))
}
func curToStats(cur *nl.XfrmLifetimeCur, wstats *nl.XfrmStats, stats *XfrmStateStats) {
stats.Bytes = cur.Bytes
stats.Packets = cur.Packets
stats.AddTime = cur.AddTime
stats.UseTime = cur.UseTime
stats.ReplayWindow = wstats.ReplayWindow
stats.Replay = wstats.Replay
stats.Failed = wstats.IntegrityFailed
}
func xfrmUsersaInfoFromXfrmState(state *XfrmState) *nl.XfrmUsersaInfo {
msg := &nl.XfrmUsersaInfo{}
msg.Family = uint16(nl.GetIPFamily(state.Dst))

View file

@ -20,9 +20,10 @@ Testing (requires root):
package main
import (
"fmt"
"net"
"runtime"
"github.com/vishvananada/netns"
"github.com/vishvananda/netns"
)
func main() {
@ -38,7 +39,7 @@ func main() {
newns, _ := netns.New()
defer newns.Close()
// Do something with tne network namespace
// Do something with the network namespace
ifaces, _ := net.Interfaces()
fmt.Printf("Interfaces: %v\n", ifaces)

View file

@ -19,7 +19,7 @@ type NsHandle int
// Equal determines if two network handles refer to the same network
// namespace. This is done by comparing the device and inode that the
// file descripors point to.
// file descriptors point to.
func (ns NsHandle) Equal(other NsHandle) bool {
if ns == other {
return true
@ -46,6 +46,19 @@ func (ns NsHandle) String() string {
return fmt.Sprintf("NS(%d: %d, %d)", ns, s.Dev, s.Ino)
}
// UniqueId returns a string which uniquely identifies the namespace
// associated with the network handle.
func (ns NsHandle) UniqueId() string {
var s syscall.Stat_t
if ns == -1 {
return "NS(none)"
}
if err := syscall.Fstat(int(ns), &s); err != nil {
return "NS(unknown)"
}
return fmt.Sprintf("NS(%d:%d)", s.Dev, s.Ino)
}
// IsOpen returns true if Close() has not been called.
func (ns NsHandle) IsOpen() bool {
return ns != -1
@ -61,7 +74,7 @@ func (ns *NsHandle) Close() error {
return nil
}
// Get an empty (closed) NsHandle
// None gets an empty (closed) NsHandle.
func None() NsHandle {
return NsHandle(-1)
}

View file

@ -7,14 +7,29 @@ import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"syscall"
)
// SYS_SETNS syscall allows changing the namespace of the current process.
var SYS_SETNS = map[string]uintptr{
"386": 346,
"amd64": 308,
"arm64": 268,
"arm": 375,
"mips": 4344,
"mipsle": 4344,
"mips64le": 4344,
"ppc64": 350,
"ppc64le": 350,
"riscv64": 268,
"s390x": 339,
}[runtime.GOARCH]
// Deprecated: use syscall pkg instead (go >= 1.5 needed).
const (
// These constants belong in the syscall library but have not been
// added yet.
CLONE_NEWUTS = 0x04000000 /* New utsname group? */
CLONE_NEWIPC = 0x08000000 /* New ipcs */
CLONE_NEWUSER = 0x10000000 /* New user namespace */
@ -39,7 +54,8 @@ func Set(ns NsHandle) (err error) {
return Setns(ns, CLONE_NEWNET)
}
// New creates a new network namespace and returns a handle to it.
// New creates a new network namespace, sets it as current and returns
// a handle to it.
func New() (ns NsHandle, err error) {
if err := syscall.Unshare(CLONE_NEWNET); err != nil {
return -1, err
@ -125,7 +141,9 @@ func getThisCgroup(cgroupType string) (string, error) {
return "", fmt.Errorf("docker pid not found in /var/run/docker.pid")
}
pid, err := strconv.Atoi(result[0])
if err != nil {
return "", err
}
output, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cgroup", pid))
if err != nil {
return "", err
@ -167,8 +185,18 @@ func getPidForContainer(id string) (int, error) {
filepath.Join(cgroupRoot, cgroupThis, id, "tasks"),
// With more recent lxc versions use, cgroup will be in lxc/
filepath.Join(cgroupRoot, cgroupThis, "lxc", id, "tasks"),
// With more recent dockee, cgroup will be in docker/
// With more recent docker, cgroup will be in docker/
filepath.Join(cgroupRoot, cgroupThis, "docker", id, "tasks"),
// Even more recent docker versions under systemd use docker-<id>.scope/
filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", "tasks"),
// Even more recent docker versions under cgroup/systemd/docker/<id>/
filepath.Join(cgroupRoot, "..", "systemd", "docker", id, "tasks"),
// Kubernetes with docker and CNI is even more different
filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "*", "pod*", id, "tasks"),
// Another flavor of containers location in recent kubernetes 1.11+
filepath.Join(cgroupRoot, cgroupThis, "kubepods.slice", "kubepods-besteffort.slice", "*", "docker-"+id+".scope", "tasks"),
// When runs inside of a container with recent kubernetes 1.11+
filepath.Join(cgroupRoot, "kubepods.slice", "kubepods-besteffort.slice", "*", "docker-"+id+".scope", "tasks"),
}
var filename string

View file

@ -1,7 +0,0 @@
// +build linux,386
package netns
const (
SYS_SETNS = 346
)

View file

@ -1,7 +0,0 @@
// +build linux,amd64
package netns
const (
SYS_SETNS = 308
)

View file

@ -1,7 +0,0 @@
// +build linux,arm
package netns
const (
SYS_SETNS = 375
)

View file

@ -1,7 +0,0 @@
// +build linux,arm64
package netns
const (
SYS_SETNS = 268
)

View file

@ -1,7 +0,0 @@
// +build linux,ppc64le
package netns
const (
SYS_SETNS = 350
)

View file

@ -1,7 +0,0 @@
// +build linux,s390x
package netns
const (
SYS_SETNS = 339
)

View file

@ -22,6 +22,10 @@ func Get() (NsHandle, error) {
return -1, ErrNotImplemented
}
func GetFromPath(path string) (NsHandle, error) {
return -1, ErrNotImplemented
}
func GetFromName(name string) (NsHandle, error) {
return -1, ErrNotImplemented
}
@ -30,6 +34,10 @@ func GetFromPid(pid int) (NsHandle, error) {
return -1, ErrNotImplemented
}
func GetFromThread(pid, tid int) (NsHandle, error) {
return -1, ErrNotImplemented
}
func GetFromDocker(id string) (NsHandle, error) {
return -1, ErrNotImplemented
}

1
vendor/go.etcd.io/bbolt/README.md generated vendored
View file

@ -929,6 +929,7 @@ Below is a list of public, open source projects that use Bolt:
* [ipxed](https://github.com/kelseyhightower/ipxed) - Web interface and api for ipxed.
* [Ironsmith](https://github.com/timshannon/ironsmith) - A simple, script-driven continuous integration (build - > test -> release) tool, with no external dependencies
* [Kala](https://github.com/ajvb/kala) - Kala is a modern job scheduler optimized to run on a single node. It is persistent, JSON over HTTP API, ISO 8601 duration notation, and dependent jobs.
* [Key Value Access Langusge (KVAL)](https://github.com/kval-access-language) - A proposed grammar for key-value datastores offering a bbolt binding.
* [LedisDB](https://github.com/siddontang/ledisdb) - A high performance NoSQL, using Bolt as optional storage.
* [lru](https://github.com/crowdriff/lru) - Easy to use Bolt-backed Least-Recently-Used (LRU) read-through cache with chainable remote stores.
* [mbuckets](https://github.com/abhigupta912/mbuckets) - A Bolt wrapper that allows easy operations on multi level (nested) buckets.

12
vendor/go.etcd.io/bbolt/bolt_riscv64.go generated vendored Normal file
View file

@ -0,0 +1,12 @@
// +build riscv64
package bbolt
// maxMapSize represents the largest mmap size supported by Bolt.
const maxMapSize = 0xFFFFFFFFFFFF // 256TB
// maxAllocSize is the size used when creating array pointers.
const maxAllocSize = 0x7FFFFFFF
// Are unaligned load/stores broken on this arch?
var brokenUnaligned = true

Some files were not shown because too many files have changed in this diff Show more