Merge branch 'master' into coolingDevice

This commit is contained in:
Ben Kochie 2019-09-09 17:44:03 +02:00 committed by GitHub
commit 82b7b1f732
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
246 changed files with 6114 additions and 1718 deletions

View file

@ -20,9 +20,11 @@
* [ENHANCEMENT] Include additional XFS runtime statistics. #1423 * [ENHANCEMENT] Include additional XFS runtime statistics. #1423
* [ENHANCEMENT] Report non-fatal collection errors in the exporter metric. #1439 * [ENHANCEMENT] Report non-fatal collection errors in the exporter metric. #1439
* [ENHANCEMENT] Expose IPVS firewall mark as a label #1455 * [ENHANCEMENT] Expose IPVS firewall mark as a label #1455
* [ENHANCEMENT] Add check for systemd version before attempting to query certain metrics. #1413
* [BUGFIX] Renamed label `state` to `name` on `node_systemd_service_restart_total`. #1393 * [BUGFIX] Renamed label `state` to `name` on `node_systemd_service_restart_total`. #1393
* [BUGFIX] Fix netdev nil reference on Darwin #1414 * [BUGFIX] Fix netdev nil reference on Darwin #1414
* [BUGFIX] Strip path.rootfs from mountpoint labels #1421 * [BUGFIX] Strip path.rootfs from mountpoint labels #1421
* [BUGFIX] Fix empty string in path.rootfs #1464
* [FEATURE] Add new thermal_zone collector #1425 * [FEATURE] Add new thermal_zone collector #1425
* [FEATURE] Add new cooling_device metrics to thermal zone collector #1445 * [FEATURE] Add new cooling_device metrics to thermal zone collector #1445

View file

@ -120,6 +120,7 @@ func TestPathRootfs(t *testing.T) {
expected := map[string]string{ expected := map[string]string{
// should modify these mountpoints (removes /host, see fixture proc file) // should modify these mountpoints (removes /host, see fixture proc file)
"/": "",
"/media/volume1": "", "/media/volume1": "",
"/media/volume2": "", "/media/volume2": "",
// should not modify these mountpoints // should not modify these mountpoints

View file

@ -1,3 +1,4 @@
/dev/nvme1n0 /host ext4 rw,seclabel,relatime,data=ordered 0 0
/dev/nvme1n1 /host/media/volume1 ext4 rw,seclabel,relatime,data=ordered 0 0 /dev/nvme1n1 /host/media/volume1 ext4 rw,seclabel,relatime,data=ordered 0 0
/dev/nvme1n2 /host/media/volume2 ext4 rw,seclabel,relatime,data=ordered 0 0 /dev/nvme1n2 /host/media/volume2 ext4 rw,seclabel,relatime,data=ordered 0 0
tmpfs /dev/shm tmpfs rw,nosuid,nodev 0 0 tmpfs /dev/shm tmpfs rw,nosuid,nodev 0 0

View file

@ -44,5 +44,9 @@ func rootfsStripPrefix(path string) string {
if *rootfsPath == "/" { if *rootfsPath == "/" {
return path return path
} }
return strings.TrimPrefix(path, *rootfsPath) stripped := strings.TrimPrefix(path, *rootfsPath)
if stripped == "" {
return "/"
}
return stripped
} }

View file

@ -19,6 +19,7 @@ import (
"fmt" "fmt"
"math" "math"
"regexp" "regexp"
"strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -29,6 +30,13 @@ import (
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
const (
// minSystemdVersionSystemState is the minimum SystemD version for availability of
// the 'SystemState' manager property and the timer property 'LastTriggerUSec'
// https://github.com/prometheus/node_exporter/issues/291
minSystemdVersionSystemState = 212
)
var ( var (
unitWhitelist = kingpin.Flag("collector.systemd.unit-whitelist", "Regexp of systemd units to whitelist. Units must both match whitelist and not match blacklist to be included.").Default(".+").String() unitWhitelist = kingpin.Flag("collector.systemd.unit-whitelist", "Regexp of systemd units to whitelist. Units must both match whitelist and not match blacklist to be included.").Default(".+").String()
unitBlacklist = kingpin.Flag("collector.systemd.unit-blacklist", "Regexp of systemd units to blacklist. Units must both match whitelist and not match blacklist to be included.").Default(".+\\.(automount|device|mount|scope|slice)").String() unitBlacklist = kingpin.Flag("collector.systemd.unit-blacklist", "Regexp of systemd units to blacklist. Units must both match whitelist and not match blacklist to be included.").Default(".+\\.(automount|device|mount|scope|slice)").String()
@ -50,6 +58,8 @@ type systemdCollector struct {
socketAcceptedConnectionsDesc *prometheus.Desc socketAcceptedConnectionsDesc *prometheus.Desc
socketCurrentConnectionsDesc *prometheus.Desc socketCurrentConnectionsDesc *prometheus.Desc
socketRefusedConnectionsDesc *prometheus.Desc socketRefusedConnectionsDesc *prometheus.Desc
systemdVersionDesc *prometheus.Desc
systemdVersion int
unitWhitelistPattern *regexp.Regexp unitWhitelistPattern *regexp.Regexp
unitBlacklistPattern *regexp.Regexp unitBlacklistPattern *regexp.Regexp
} }
@ -103,9 +113,18 @@ func NewSystemdCollector() (Collector, error) {
socketRefusedConnectionsDesc := prometheus.NewDesc( socketRefusedConnectionsDesc := prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "socket_refused_connections_total"), prometheus.BuildFQName(namespace, subsystem, "socket_refused_connections_total"),
"Total number of refused socket connections", []string{"name"}, nil) "Total number of refused socket connections", []string{"name"}, nil)
systemdVersionDesc := prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "version"),
"Detected systemd version", []string{}, nil)
unitWhitelistPattern := regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *unitWhitelist)) unitWhitelistPattern := regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *unitWhitelist))
unitBlacklistPattern := regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *unitBlacklist)) unitBlacklistPattern := regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *unitBlacklist))
systemdVersion := getSystemdVersion()
if systemdVersion < minSystemdVersionSystemState {
log.Warnf("Detected systemd version %v is lower than minimum %v", systemdVersion, minSystemdVersionSystemState)
log.Warn("Some systemd state and timer metrics will not be available")
}
return &systemdCollector{ return &systemdCollector{
unitDesc: unitDesc, unitDesc: unitDesc,
unitStartTimeDesc: unitStartTimeDesc, unitStartTimeDesc: unitStartTimeDesc,
@ -118,6 +137,8 @@ func NewSystemdCollector() (Collector, error) {
socketAcceptedConnectionsDesc: socketAcceptedConnectionsDesc, socketAcceptedConnectionsDesc: socketAcceptedConnectionsDesc,
socketCurrentConnectionsDesc: socketCurrentConnectionsDesc, socketCurrentConnectionsDesc: socketCurrentConnectionsDesc,
socketRefusedConnectionsDesc: socketRefusedConnectionsDesc, socketRefusedConnectionsDesc: socketRefusedConnectionsDesc,
systemdVersionDesc: systemdVersionDesc,
systemdVersion: systemdVersion,
unitWhitelistPattern: unitWhitelistPattern, unitWhitelistPattern: unitWhitelistPattern,
unitBlacklistPattern: unitBlacklistPattern, unitBlacklistPattern: unitBlacklistPattern,
}, nil }, nil
@ -127,7 +148,7 @@ func NewSystemdCollector() (Collector, error) {
// to reduce wait time for responses. // to reduce wait time for responses.
func (c *systemdCollector) Update(ch chan<- prometheus.Metric) error { func (c *systemdCollector) Update(ch chan<- prometheus.Metric) error {
begin := time.Now() begin := time.Now()
conn, err := c.newDbus() conn, err := newSystemdDbusConn()
if err != nil { if err != nil {
return fmt.Errorf("couldn't get dbus connection: %s", err) return fmt.Errorf("couldn't get dbus connection: %s", err)
} }
@ -179,13 +200,15 @@ func (c *systemdCollector) Update(ch chan<- prometheus.Metric) error {
}() }()
} }
wg.Add(1) if c.systemdVersion >= minSystemdVersionSystemState {
go func() { wg.Add(1)
defer wg.Done() go func() {
begin = time.Now() defer wg.Done()
c.collectTimers(conn, ch, units) begin = time.Now()
log.Debugf("systemd collectTimers took %f", time.Since(begin).Seconds()) c.collectTimers(conn, ch, units)
}() log.Debugf("systemd collectTimers took %f", time.Since(begin).Seconds())
}()
}
wg.Add(1) wg.Add(1)
go func() { go func() {
@ -195,9 +218,15 @@ func (c *systemdCollector) Update(ch chan<- prometheus.Metric) error {
log.Debugf("systemd collectSockets took %f", time.Since(begin).Seconds()) log.Debugf("systemd collectSockets took %f", time.Since(begin).Seconds())
}() }()
begin = time.Now() if c.systemdVersion >= minSystemdVersionSystemState {
err = c.collectSystemState(conn, ch) begin = time.Now()
log.Debugf("systemd collectSystemState took %f", time.Since(begin).Seconds()) err = c.collectSystemState(conn, ch)
log.Debugf("systemd collectSystemState took %f", time.Since(begin).Seconds())
}
ch <- prometheus.MustNewConstMetric(
c.systemdVersionDesc, prometheus.GaugeValue, float64(c.systemdVersion))
return err return err
} }
@ -369,7 +398,7 @@ func (c *systemdCollector) collectSystemState(conn *dbus.Conn, ch chan<- prometh
return nil return nil
} }
func (c *systemdCollector) newDbus() (*dbus.Conn, error) { func newSystemdDbusConn() (*dbus.Conn, error) {
if *systemdPrivate { if *systemdPrivate {
return dbus.NewSystemdConnection() return dbus.NewSystemdConnection()
} }
@ -424,3 +453,24 @@ func filterUnits(units []unit, whitelistPattern, blacklistPattern *regexp.Regexp
return filtered return filtered
} }
func getSystemdVersion() int {
conn, err := newSystemdDbusConn()
if err != nil {
log.Warnf("Unable to get systemd dbus connection, defaulting systemd version to 0: %s", err)
return 0
}
defer conn.Close()
version, err := conn.GetManagerProperty("Version")
if err != nil {
log.Warn("Unable to get systemd version property, defaulting to 0")
return 0
}
version = strings.Replace(version, "\"", "", 2)
v, err := strconv.Atoi(version)
if err != nil {
log.Warnf("Got invalid systemd version: %v", version)
return 0
}
return v
}

View file

@ -39,6 +39,9 @@ for Grafana:
$ make dashboards_out $ make dashboards_out
``` ```
Note that some of the generated dashboards require recording rules specified in
the previously generated `node_rules.yaml`.
For more advanced uses of mixins, see For more advanced uses of mixins, see
https://github.com/monitoring-mixins/docs. https://github.com/monitoring-mixins/docs.

10
go.mod
View file

@ -3,15 +3,14 @@ module github.com/prometheus/node_exporter
require ( require (
github.com/beevik/ntp v0.2.0 github.com/beevik/ntp v0.2.0
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e
github.com/ema/qdisc v0.0.0-20180104102928-b307c22d3ce7 github.com/ema/qdisc v0.0.0-20190904071900-b82c76788043
github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968 github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968
github.com/hodgesds/perf-utils v0.0.7 github.com/hodgesds/perf-utils v0.0.7
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/lufia/iostat v0.0.0-20170605150913-9f7362b77ad3 github.com/lufia/iostat v0.0.0-20170605150913-9f7362b77ad3
github.com/mattn/go-xmlrpc v0.0.1 github.com/mattn/go-xmlrpc v0.0.1
github.com/mdlayher/genetlink v0.0.0-20181016160152-e97704c1b795 // indirect github.com/mdlayher/genetlink v0.0.0-20190828143517-e35f2bf499b9 // indirect
github.com/mdlayher/netlink v0.0.0-20181210160939-e069752bc835 // indirect github.com/mdlayher/wifi v0.0.0-20190303161829-b1436901ddee
github.com/mdlayher/wifi v0.0.0-20180727163819-efdf3f4195d9
github.com/prometheus/client_golang v1.0.0 github.com/prometheus/client_golang v1.0.0
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90
github.com/prometheus/common v0.4.1 github.com/prometheus/common v0.4.1
@ -21,8 +20,7 @@ require (
github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a
go.uber.org/atomic v1.3.2 // indirect go.uber.org/atomic v1.3.2 // indirect
go.uber.org/multierr v1.1.0 // indirect go.uber.org/multierr v1.1.0 // indirect
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c // indirect
golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect
golang.org/x/sys v0.0.0-20190610081024-1e42afee0f76 golang.org/x/sys v0.0.0-20190902133755-9109b7679e13
gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/alecthomas/kingpin.v2 v2.2.6
) )

35
go.sum
View file

@ -13,8 +13,8 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/ema/qdisc v0.0.0-20180104102928-b307c22d3ce7 h1:jzWRD7cjz7ditpwbTbQdnHzFFW3KIFAVw9Ia5C0n/zs= github.com/ema/qdisc v0.0.0-20190904071900-b82c76788043 h1:I3hLsM87FSASssIrIOGwJCio31dvLkvpYDKn2+r31ec=
github.com/ema/qdisc v0.0.0-20180104102928-b307c22d3ce7/go.mod h1:kXuKAameaga9ciOgiYWAM85FQP+wt5aN4uX+9OHVJe4= github.com/ema/qdisc v0.0.0-20190904071900-b82c76788043/go.mod h1:ix4kG2zvdUd8kEKSW0ZTr1XLks0epFpI4j745DXxlNE=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@ -26,10 +26,16 @@ github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/hodgesds/perf-utils v0.0.7 h1:V/5aRKeXn/membOpFdzAgd+fFvmtvTYD6moDuZ7K7SM= github.com/hodgesds/perf-utils v0.0.7 h1:V/5aRKeXn/membOpFdzAgd+fFvmtvTYD6moDuZ7K7SM=
github.com/hodgesds/perf-utils v0.0.7/go.mod h1:F6TfvsbtrF88i++hou29dTXlI2sfsJv+gRZDtmTJkAs= github.com/hodgesds/perf-utils v0.0.7/go.mod h1:F6TfvsbtrF88i++hou29dTXlI2sfsJv+gRZDtmTJkAs=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/jsimonetti/rtnetlink v0.0.0-20190830100107-3784a6c7c552 h1:Ve/e6edHdAHn+8/24Xco7IhQCv3u5Dab2qZNvR9e5/U=
github.com/jsimonetti/rtnetlink v0.0.0-20190830100107-3784a6c7c552/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
@ -43,12 +49,13 @@ github.com/mattn/go-xmlrpc v0.0.1 h1:JY8G+sH4jcjzZvxAY5P+wNrWA2WYC+aK+2bsYOl4z0Q
github.com/mattn/go-xmlrpc v0.0.1/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA= github.com/mattn/go-xmlrpc v0.0.1/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mdlayher/genetlink v0.0.0-20181016160152-e97704c1b795 h1:2uvgdCvQ/MUubxqVhOFkeTaI0EZLcjPLVIwgZGWPgxs= github.com/mdlayher/genetlink v0.0.0-20190828143517-e35f2bf499b9 h1:o+ckyx58UC6Itoo7sEwmXMpHcnI31lRK6w4M5gQMIMw=
github.com/mdlayher/genetlink v0.0.0-20181016160152-e97704c1b795/go.mod h1:EOrmeik1bDMaRduo2B+uAYe1HmTq6yF2IMDmJi1GoWk= github.com/mdlayher/genetlink v0.0.0-20190828143517-e35f2bf499b9/go.mod h1:jdlTGSEt8SRUJPk5+vLsPyojmLVAxsOKNjVkqrixnJ8=
github.com/mdlayher/netlink v0.0.0-20181210160939-e069752bc835 h1:WpZONc7LNdfPrld0YIt2aOiy9T66FfRCqZDrsDkWJX0= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
github.com/mdlayher/netlink v0.0.0-20181210160939-e069752bc835/go.mod h1:a3TlQHkJH2m32RF224Z7LhD5N4mpyR8eUbCoYHywrwg= github.com/mdlayher/netlink v0.0.0-20190828143259-340058475d09 h1:U2vuol6i4UF6MSpZJclH4HHiLRMoq1NAzxpIpCUJK/Y=
github.com/mdlayher/wifi v0.0.0-20180727163819-efdf3f4195d9 h1:ag57ienknXLMhoSbkYvaZLF9Taxu9GtBHUJ4jP5ER8s= github.com/mdlayher/netlink v0.0.0-20190828143259-340058475d09/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
github.com/mdlayher/wifi v0.0.0-20180727163819-efdf3f4195d9/go.mod h1:Evt/EIne46u9PtQbeTx2NTcqURpr5K4SvKtGmBuDPN8= github.com/mdlayher/wifi v0.0.0-20190303161829-b1436901ddee h1:hZDujBrW3ye2xxdKNFYT59D4yCH5Q0zLuNBNtysKtok=
github.com/mdlayher/wifi v0.0.0-20190303161829-b1436901ddee/go.mod h1:Evt/EIne46u9PtQbeTx2NTcqURpr5K4SvKtGmBuDPN8=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@ -90,8 +97,9 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
@ -101,9 +109,12 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190610081024-1e42afee0f76 h1:QSmW7Q3mFdAGjtAd0byXmFJ55inUydyZ4WQmiuItAIQ= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190610081024-1e42afee0f76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190902133755-9109b7679e13 h1:tdsQdquKbTNMsSZLqnLELJGzCANp9oXhu6zFBW6ODx4=
golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=

View file

@ -1,16 +1,16 @@
language: go language: go
go: go:
- 1.x - 1.x
env:
- GO111MODULE=on
os: os:
- linux - linux
sudo: required sudo: required
before_install: before_install:
- go get github.com/golang/lint/golint - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.17.1
- go get honnef.co/go/tools/cmd/staticcheck
- go get -d ./... - go get -d ./...
script: script:
- go build -tags=gofuzz ./... - go build -tags=gofuzz ./...
- go vet ./... - go vet ./...
- staticcheck ./... - golangci-lint run ./...
#- golint -set_exit_status ./...
- go test -v -race -tags=integration ./... - go test -v -race -tags=integration ./...

10
vendor/github.com/ema/qdisc/get.go generated vendored
View file

@ -19,7 +19,7 @@ const (
TCA_FCNT TCA_FCNT
TCA_STATS2 TCA_STATS2
TCA_STAB TCA_STAB
__TCA_MAX // __TCA_MAX
) )
const ( const (
@ -29,7 +29,7 @@ const (
TCA_STATS_QUEUE TCA_STATS_QUEUE
TCA_STATS_APP TCA_STATS_APP
TCA_STATS_RATE_EST64 TCA_STATS_RATE_EST64
__TCA_STATS_MAX // __TCA_STATS_MAX
) )
// See struct tc_stats in /usr/include/linux/pkt_sched.h // See struct tc_stats in /usr/include/linux/pkt_sched.h
@ -157,10 +157,10 @@ func parseTC_Fq_Qd_Stats(attr netlink.Attribute) (TC_Fq_Qd_Stats, error) {
func getQdiscMsgs(c *netlink.Conn) ([]netlink.Message, error) { func getQdiscMsgs(c *netlink.Conn) ([]netlink.Message, error) {
req := netlink.Message{ req := netlink.Message{
Header: netlink.Header{ Header: netlink.Header{
Flags: netlink.HeaderFlagsRequest | netlink.HeaderFlagsDump, Flags: netlink.Request | netlink.Dump,
Type: 38, // RTM_GETQDISC Type: 38, // RTM_GETQDISC
}, },
Data: []byte{0}, Data: make([]byte, 20),
} }
// Perform a request, receive replies, and validate the replies // Perform a request, receive replies, and validate the replies
@ -192,7 +192,7 @@ func parseMessage(msg netlink.Message) (QdiscInfo, error) {
*/ */
if len(msg.Data) < 20 { if len(msg.Data) < 20 {
return m, fmt.Errorf("Short message, len=%d", len(msg.Data)) return m, fmt.Errorf("short message, len=%d", len(msg.Data))
} }
ifaceIdx := nlenc.Uint32(msg.Data[4:8]) ifaceIdx := nlenc.Uint32(msg.Data[4:8])

9
vendor/github.com/ema/qdisc/go.mod generated vendored Normal file
View file

@ -0,0 +1,9 @@
module github.com/ema/qdisc
go 1.12
require (
github.com/jsimonetti/rtnetlink v0.0.0-20190830100107-3784a6c7c552 // indirect
github.com/mdlayher/netlink v0.0.0-20190828143259-340058475d09
golang.org/x/sys v0.0.0-20190902133755-9109b7679e13 // indirect
)

20
vendor/github.com/ema/qdisc/go.sum generated vendored Normal file
View file

@ -0,0 +1,20 @@
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/jsimonetti/rtnetlink v0.0.0-20190830100107-3784a6c7c552 h1:Ve/e6edHdAHn+8/24Xco7IhQCv3u5Dab2qZNvR9e5/U=
github.com/jsimonetti/rtnetlink v0.0.0-20190830100107-3784a6c7c552/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
github.com/mdlayher/netlink v0.0.0-20190828143259-340058475d09 h1:U2vuol6i4UF6MSpZJclH4HHiLRMoq1NAzxpIpCUJK/Y=
github.com/mdlayher/netlink v0.0.0-20190828143259-340058475d09/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190902133755-9109b7679e13 h1:tdsQdquKbTNMsSZLqnLELJGzCANp9oXhu6zFBW6ODx4=
golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View file

@ -1,16 +0,0 @@
language: go
go:
- 1.x
os:
- linux
sudo: required
before_install:
- go get golang.org/x/lint/golint
- go get honnef.co/go/tools/cmd/staticcheck
- go get -d ./...
script:
- go build -tags=gofuzz ./...
- go vet ./...
- staticcheck ./...
- golint -set_exit_status ./...
- go test -v -race -tags=integration ./...

View file

@ -1,8 +1,12 @@
genetlink [![Build Status](https://travis-ci.org/mdlayher/genetlink.svg?branch=master)](https://travis-ci.org/mdlayher/genetlink) [![GoDoc](https://godoc.org/github.com/mdlayher/genetlink?status.svg)](https://godoc.org/github.com/mdlayher/genetlink) [![Go Report Card](https://goreportcard.com/badge/github.com/mdlayher/genetlink)](https://goreportcard.com/report/github.com/mdlayher/genetlink) genetlink [![builds.sr.ht status](https://builds.sr.ht/~mdlayher/genetlink.svg)](https://builds.sr.ht/~mdlayher/genetlink?) [![GoDoc](https://godoc.org/github.com/mdlayher/genetlink?status.svg)](https://godoc.org/github.com/mdlayher/genetlink) [![Go Report Card](https://goreportcard.com/badge/github.com/mdlayher/genetlink)](https://goreportcard.com/report/github.com/mdlayher/genetlink)
========= =========
Package `genetlink` implements generic netlink interactions and data types. Package `genetlink` implements generic netlink interactions and data types.
MIT Licensed. MIT Licensed.
For more information about how netlink and generic netlink work, For more information about how netlink and generic netlink work,
check out my blog series on [Linux, Netlink, and Go](https://medium.com/@mdlayher/linux-netlink-and-go-part-1-netlink-4781aaeeaca8). check out my blog series on [Linux, Netlink, and Go](https://mdlayher.com/blog/linux-netlink-and-go-part-1-netlink/).
If you have any questions or you'd like some guidance, please join us on
[Gophers Slack](https://invite.slack.golangbridge.org) in the `#networking`
channel!

View file

@ -2,6 +2,7 @@ package genetlink
import ( import (
"syscall" "syscall"
"time"
"github.com/mdlayher/netlink" "github.com/mdlayher/netlink"
"golang.org/x/net/bpf" "golang.org/x/net/bpf"
@ -10,8 +11,12 @@ import (
// Protocol is the netlink protocol constant used to specify generic netlink. // Protocol is the netlink protocol constant used to specify generic netlink.
const Protocol = 0x10 // unix.NETLINK_GENERIC const Protocol = 0x10 // unix.NETLINK_GENERIC
// A Conn is a generic netlink connection. A Conn can be used to send and // A Conn is a generic netlink connection. A Conn can be used to send and
// receive generic netlink messages to and from netlink. // receive generic netlink messages to and from netlink.
//
// A Conn is safe for concurrent use, but to avoid contention in
// high-throughput applications, the caller should almost certainly create a
// pool of Conns and distribute them among workers.
type Conn struct { type Conn struct {
// Operating system-specific netlink connection. // Operating system-specific netlink connection.
c *netlink.Conn c *netlink.Conn
@ -38,13 +43,16 @@ func NewConn(c *netlink.Conn) *Conn {
return &Conn{c: c} return &Conn{c: c}
} }
// Close closes the connection. // Close closes the connection. Close will unblock any concurrent calls to
// Receive which are waiting on a response from the kernel.
func (c *Conn) Close() error { func (c *Conn) Close() error {
return c.c.Close() return c.c.Close()
} }
// GetFamily retrieves a generic netlink family with the specified name. If the // GetFamily retrieves a generic netlink family with the specified name.
// family does not exist, the error value can be checked using os.IsNotExist. //
// If the family does not exist, the error value can be checked using
// netlink.IsNotExist.
func (c *Conn) GetFamily(name string) (Family, error) { func (c *Conn) GetFamily(name string) (Family, error) {
return c.getFamily(name) return c.getFamily(name)
} }
@ -94,8 +102,10 @@ func (c *Conn) SetWriteBuffer(bytes int) error {
// SyscallConn returns a raw network connection. This implements the // SyscallConn returns a raw network connection. This implements the
// syscall.Conn interface. // syscall.Conn interface.
// //
// Only the Control method of the returned syscall.RawConn is currently // On Go 1.12+, all methods of the returned syscall.RawConn are supported and
// implemented. // the Conn is integrated with the runtime network poller. On versions of Go
// prior to Go 1.12, only the Control method of the returned syscall.RawConn
// is implemented.
// //
// SyscallConn is intended for advanced use cases, such as getting and setting // SyscallConn is intended for advanced use cases, such as getting and setting
// arbitrary socket options using the netlink socket's file descriptor. // arbitrary socket options using the netlink socket's file descriptor.
@ -107,23 +117,39 @@ func (c *Conn) SyscallConn() (syscall.RawConn, error) {
return c.c.SyscallConn() return c.c.SyscallConn()
} }
// SetDeadline sets the read and write deadlines associated with the connection.
//
// Deadline functionality is only supported on Go 1.12+. Calling this function
// on older versions of Go will result in an error.
func (c *Conn) SetDeadline(t time.Time) error {
return c.c.SetDeadline(t)
}
// SetReadDeadline sets the read deadline associated with the connection.
//
// Deadline functionality is only supported on Go 1.12+. Calling this function
// on older versions of Go will result in an error.
func (c *Conn) SetReadDeadline(t time.Time) error {
return c.c.SetReadDeadline(t)
}
// SetWriteDeadline sets the write deadline associated with the connection.
//
// Deadline functionality is only supported on Go 1.12+. Calling this function
// on older versions of Go will result in an error.
func (c *Conn) SetWriteDeadline(t time.Time) error {
return c.c.SetWriteDeadline(t)
}
// Send sends a single Message to netlink, wrapping it in a netlink.Message // Send sends a single Message to netlink, wrapping it in a netlink.Message
// using the specified generic netlink family and flags. On success, Send // using the specified generic netlink family and flags. On success, Send
// returns a copy of the netlink.Message with all parameters populated, for // returns a copy of the netlink.Message with all parameters populated, for
// later validation. // later validation.
func (c *Conn) Send(m Message, family uint16, flags netlink.HeaderFlags) (netlink.Message, error) { func (c *Conn) Send(m Message, family uint16, flags netlink.HeaderFlags) (netlink.Message, error) {
nm := netlink.Message{ nm, err := packMessage(m, family, flags)
Header: netlink.Header{
Type: netlink.HeaderType(family),
Flags: flags,
},
}
mb, err := m.MarshalBinary()
if err != nil { if err != nil {
return netlink.Message{}, err return netlink.Message{}, err
} }
nm.Data = mb
reqnm, err := c.c.Send(nm) reqnm, err := c.c.Send(nm)
if err != nil { if err != nil {
@ -141,39 +167,69 @@ func (c *Conn) Receive() ([]Message, []netlink.Message, error) {
return nil, nil, err return nil, nil, err
} }
gmsgs := make([]Message, 0, len(msgs)) gmsgs, err := unpackMessages(msgs)
for _, nm := range msgs { if err != nil {
var gm Message return nil, nil, err
if err := (&gm).UnmarshalBinary(nm.Data); err != nil {
return nil, nil, err
}
gmsgs = append(gmsgs, gm)
} }
return gmsgs, msgs, nil return gmsgs, msgs, nil
} }
// Execute sends a single Message to netlink using Conn.Send, receives one or // Execute sends a single Message to netlink using Send, receives one or more
// more replies using Conn.Receive, and then checks the validity of the replies // replies using Receive, and then checks the validity of the replies against
// against the request using netlink.Validate. // the request using netlink.Validate.
// //
// See the documentation of Conn.Send, Conn.Receive, and netlink.Validate for // Execute acquires a lock for the duration of the function call which blocks
// details about each function. // concurrent calls to Send and Receive, in order to ensure consistency between
// generic netlink request/reply messages.
//
// See the documentation of Send, Receive, and netlink.Validate for details
// about each function.
func (c *Conn) Execute(m Message, family uint16, flags netlink.HeaderFlags) ([]Message, error) { func (c *Conn) Execute(m Message, family uint16, flags netlink.HeaderFlags) ([]Message, error) {
req, err := c.Send(m, family, flags) nm, err := packMessage(m, family, flags)
if err != nil { if err != nil {
return nil, err return nil, err
} }
msgs, replies, err := c.Receive() // Locking behavior handled by netlink.Conn.Execute.
msgs, err := c.c.Execute(nm)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := netlink.Validate(req, replies); err != nil { return unpackMessages(msgs)
return nil, err }
}
// packMessage packs a generic netlink Message into a netlink.Message with the
return msgs, nil // appropriate generic netlink family and netlink flags.
func packMessage(m Message, family uint16, flags netlink.HeaderFlags) (netlink.Message, error) {
nm := netlink.Message{
Header: netlink.Header{
Type: netlink.HeaderType(family),
Flags: flags,
},
}
mb, err := m.MarshalBinary()
if err != nil {
return netlink.Message{}, err
}
nm.Data = mb
return nm, nil
}
// unpackMessages unpacks generic netlink Messages from a slice of netlink.Messages.
func unpackMessages(msgs []netlink.Message) ([]Message, error) {
gmsgs := make([]Message, 0, len(msgs))
for _, nm := range msgs {
var gm Message
if err := (&gm).UnmarshalBinary(nm.Data); err != nil {
return nil, err
}
gmsgs = append(gmsgs, gm)
}
return gmsgs, nil
} }

View file

@ -1,2 +1,6 @@
// Package genetlink implements generic netlink interactions and data types. // Package genetlink implements generic netlink interactions and data types.
//
// If you have any questions or you'd like some guidance, please join us on
// Gophers Slack (https://invite.slack.golangbridge.org) in the #networking
// channel!
package genetlink package genetlink

View file

@ -12,11 +12,9 @@ import (
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
var ( // errInvalidFamilyVersion is returned when a family's version is greater
// errInvalidFamilyVersion is returned when a family's version is greater // than an 8-bit integer.
// than an 8-bit integer. var errInvalidFamilyVersion = errors.New("invalid family version attribute")
errInvalidFamilyVersion = errors.New("invalid family version attribute")
)
// getFamily retrieves a generic netlink family with the specified name. // getFamily retrieves a generic netlink family with the specified name.
func (c *Conn) getFamily(name string) (Family, error) { func (c *Conn) getFamily(name string) (Family, error) {
@ -37,7 +35,7 @@ func (c *Conn) getFamily(name string) (Family, error) {
Data: b, Data: b,
} }
msgs, err := c.Execute(req, unix.GENL_ID_CTRL, netlink.HeaderFlagsRequest) msgs, err := c.Execute(req, unix.GENL_ID_CTRL, netlink.Request)
if err != nil { if err != nil {
return Family{}, err return Family{}, err
} }
@ -67,7 +65,7 @@ func (c *Conn) listFamilies() ([]Family, error) {
}, },
} }
flags := netlink.HeaderFlagsRequest | netlink.HeaderFlagsDump flags := netlink.Request | netlink.Dump
msgs, err := c.Execute(req, unix.GENL_ID_CTRL, flags) msgs, err := c.Execute(req, unix.GENL_ID_CTRL, flags)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -7,12 +7,10 @@ import (
"runtime" "runtime"
) )
var ( // errUnimplemented is returned by all functions on platforms that
// errUnimplemented is returned by all functions on platforms that // cannot make use of generic netlink.
// cannot make use of generic netlink. var errUnimplemented = fmt.Errorf("generic netlink not implemented on %s/%s",
errUnimplemented = fmt.Errorf("generic netlink not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
runtime.GOOS, runtime.GOARCH)
)
// getFamily always returns an error. // getFamily always returns an error.
func (c *Conn) getFamily(name string) (Family, error) { func (c *Conn) getFamily(name string) (Family, error) {

10
vendor/github.com/mdlayher/genetlink/go.mod generated vendored Normal file
View file

@ -0,0 +1,10 @@
module github.com/mdlayher/genetlink
go 1.12
require (
github.com/google/go-cmp v0.3.1
github.com/mdlayher/netlink v0.0.0-20190828143259-340058475d09
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456
)

18
vendor/github.com/mdlayher/genetlink/go.sum generated vendored Normal file
View file

@ -0,0 +1,18 @@
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a h1:84IpUNXj4mCR9CuCEvSiCArMbzr/TMbuPIadKDwypkI=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
github.com/mdlayher/netlink v0.0.0-20190828143259-340058475d09 h1:U2vuol6i4UF6MSpZJclH4HHiLRMoq1NAzxpIpCUJK/Y=
github.com/mdlayher/netlink v0.0.0-20190828143259-340058475d09/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View file

@ -1,15 +1,11 @@
package genetlink package genetlink
import ( import "errors"
"errors"
)
var ( // errInvalidMessage is returned when a Message is malformed.
// errInvalidMessage is returned when a Message is malformed. var errInvalidMessage = errors.New("generic netlink message is invalid or too short")
errInvalidMessage = errors.New("generic netlink message is invalid or too short")
)
// A Header is a generic netlink header. A Header is sent and received with // A Header is a generic netlink header. A Header is sent and received with
// each generic netlink message to indicate metadata regarding a Message. // each generic netlink message to indicate metadata regarding a Message.
type Header struct { type Header struct {
// Command specifies a command to issue to netlink. // Command specifies a command to issue to netlink.
@ -22,13 +18,13 @@ type Header struct {
// headerLen is the length of a Header. // headerLen is the length of a Header.
const headerLen = 4 // unix.GENL_HDRLEN const headerLen = 4 // unix.GENL_HDRLEN
// A Message is a generic netlink message. It contains a Header and an // A Message is a generic netlink message. It contains a Header and an
// arbitrary byte payload, which may be decoded using information from the // arbitrary byte payload, which may be decoded using information from the
// Header. // Header.
// //
// Data is encoded using the native endianness of the host system. Use // Data is encoded using the native endianness of the host system. Use
// the netlink.Uint* and netlink.PutUint* functions to encode and decode // the netlink.AttributeDecoder and netlink.AttributeEncoder types to decode
// integers. // and encode data.
type Message struct { type Message struct {
Header Header Header Header
Data []byte Data []byte

View file

@ -1 +1,2 @@
cmd/nlstress/nlstress cmd/nlstress/nlstress
netlink.test

View file

@ -1,17 +0,0 @@
language: go
go:
- "1.x"
os:
- linux
- osx
sudo: required
before_install:
- go get golang.org/x/lint/golint
- go get honnef.co/go/tools/cmd/staticcheck
- go get -d ./...
script:
- go build -tags=gofuzz ./...
- go vet ./...
- staticcheck ./...
- golint -set_exit_status ./...
- go test -v -race -tags=integration ./...

View file

@ -1,7 +1,7 @@
MIT License MIT License
=========== ===========
Copyright (C) 2016-2017 Matt Layher Copyright (C) 2016-2019 Matt Layher
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View file

@ -1,27 +1,49 @@
netlink [![Build Status](https://travis-ci.org/mdlayher/netlink.svg?branch=master)](https://travis-ci.org/mdlayher/netlink) [![GoDoc](https://godoc.org/github.com/mdlayher/netlink?status.svg)](https://godoc.org/github.com/mdlayher/netlink) [![Go Report Card](https://goreportcard.com/badge/github.com/mdlayher/netlink)](https://goreportcard.com/report/github.com/mdlayher/netlink) # netlink [![builds.sr.ht status](https://builds.sr.ht/~mdlayher/netlink.svg)](https://builds.sr.ht/~mdlayher/netlink?) [![GoDoc](https://godoc.org/github.com/mdlayher/netlink?status.svg)](https://godoc.org/github.com/mdlayher/netlink) [![Go Report Card](https://goreportcard.com/badge/github.com/mdlayher/netlink)](https://goreportcard.com/report/github.com/mdlayher/netlink)
=======
Package `netlink` provides low-level access to Linux netlink sockets. Package `netlink` provides low-level access to Linux netlink sockets.
MIT Licensed. MIT Licensed.
For more information about how netlink works, check out my blog series For more information about how netlink works, check out my blog series
on [Linux, Netlink, and Go](https://medium.com/@mdlayher/linux-netlink-and-go-part-1-netlink-4781aaeeaca8). on [Linux, Netlink, and Go](https://mdlayher.com/blog/linux-netlink-and-go-part-1-netlink/).
If you're looking for package `genetlink`, it's been moved to its own If you have any questions or you'd like some guidance, please join us on
repository at [`github.com/mdlayher/genetlink`](https://github.com/mdlayher/genetlink). [Gophers Slack](https://invite.slack.golangbridge.org) in the `#networking`
channel!
Why? ## Stability
----
At this time, package `netlink` is in a pre-v1.0.0 state. Changes are being made
which may impact the exported API of this package and others in its ecosystem.
To follow along on the status of a v1.0.0 release, [see the associated issue](https://github.com/mdlayher/netlink/issues/123).
The general policy of this package is to only support the latest, stable version
of Go. Compatibility shims may be added for prior versions of Go on an as-needed
basis. If you would like to raise a concern, please [file an issue](https://github.com/mdlayher/netlink/issues/new).
**If you depend on this package in your applications, please vendor it or use Go
modules when building your application.**
## Design
A [number of netlink packages](https://godoc.org/?q=netlink) are already A [number of netlink packages](https://godoc.org/?q=netlink) are already
available for Go, but I wasn't able to find one that aligned with what available for Go, but I wasn't able to find one that aligned with what
I wanted in a netlink package: I wanted in a netlink package:
- Simple, idiomatic API - Straightforward, idiomatic API
- Well tested - Well tested
- Well documented - Well documented
- Makes use of Go best practices - Doesn't use package/global variables or state
- Doesn't need root to work - Doesn't necessarily need root to work
My goal for this package is to use it as a building block for the creation My goal for this package is to use it as a building block for the creation
of other netlink family packages. of other netlink family packages.
## Ecosystem
Over time, an ecosystem of Go packages has developed around package `netlink`.
Many of these packages provide building blocks for further interactions with
various netlink families, such as `NETLINK_GENERIC` or `NETLINK_ROUTE`.
To have your package included in this diagram, please send a pull request!
![netlink ecosystem](./netlink.svg)

View file

@ -1,8 +1,6 @@
package netlink package netlink
import ( import "unsafe"
"unsafe"
)
// Functions and values used to properly align netlink messages, headers, // Functions and values used to properly align netlink messages, headers,
// and attributes. Definitions taken from Linux kernel source. // and attributes. Definitions taken from Linux kernel source.

View file

@ -8,10 +8,8 @@ import (
"github.com/mdlayher/netlink/nlenc" "github.com/mdlayher/netlink/nlenc"
) )
var ( // errInvalidAttribute specifies if an Attribute's length is incorrect.
// errInvalidAttribute specifies if an Attribute's length is incorrect. var errInvalidAttribute = errors.New("invalid attribute; length too short or too large")
errInvalidAttribute = errors.New("invalid attribute; length too short or too large")
)
// An Attribute is a netlink attribute. Attributes are packed and unpacked // An Attribute is a netlink attribute. Attributes are packed and unpacked
// to and from the Data field of Message for some netlink families. // to and from the Data field of Message for some netlink families.
@ -180,12 +178,8 @@ func (ad *AttributeDecoder) Next() bool {
ad.i++ ad.i++
if len(ad.attrs) < ad.i { // More attributes?
// No more attributes, stop iteration. return len(ad.attrs) >= ad.i
return false
}
return true
} }
// Type returns the Attribute.Type field of the current netlink attribute // Type returns the Attribute.Type field of the current netlink attribute

View file

@ -2,9 +2,9 @@ package netlink
import ( import (
"errors" "errors"
"io"
"math/rand" "math/rand"
"os" "os"
"sync"
"sync/atomic" "sync/atomic"
"syscall" "syscall"
"time" "time"
@ -12,30 +12,16 @@ import (
"golang.org/x/net/bpf" "golang.org/x/net/bpf"
) )
// Error messages which can be returned by Validate.
var (
errMismatchedSequence = errors.New("mismatched sequence in netlink reply")
errMismatchedPID = errors.New("mismatched PID in netlink reply")
errShortErrorMessage = errors.New("not enough data for netlink error code")
)
// Errors which can be returned by a Socket that does not implement
// all exposed methods of Conn.
var (
errReadWriteCloserNotSupported = errors.New("raw read/write/closer not supported")
errMulticastGroupsNotSupported = errors.New("multicast groups not supported")
errBPFFiltersNotSupported = errors.New("BPF filters not supported")
errOptionsNotSupported = errors.New("options not supported")
errSetBufferNotSupported = errors.New("setting buffer sizes not supported")
errSyscallConnNotSupported = errors.New("syscall.RawConn operation not supported")
)
// A Conn is a connection to netlink. A Conn can be used to send and // A Conn is a connection to netlink. A Conn can be used to send and
// receives messages to and from netlink. // receives messages to and from netlink.
// //
// A Conn is safe for concurrent use, but to avoid contention in // A Conn is safe for concurrent use, but to avoid contention in
// high-throughput applications, the caller should almost certainly create a // high-throughput applications, the caller should almost certainly create a
// pool of Conns and distribute them among workers. // pool of Conns and distribute them among workers.
//
// A Conn is capable of manipulating netlink subsystems from within a specific
// Linux network namespace, but special care must be taken when doing so. See
// the documentation of Config for details.
type Conn struct { type Conn struct {
// sock is the operating system-specific implementation of // sock is the operating system-specific implementation of
// a netlink sockets connection. // a netlink sockets connection.
@ -50,6 +36,10 @@ type Conn struct {
// d provides debugging capabilities for a Conn if not nil. // d provides debugging capabilities for a Conn if not nil.
d *debugger d *debugger
// mu serializes access to the netlink socket for the request/response
// transaction within Execute.
mu sync.RWMutex
} }
// A Socket is an operating-system specific implementation of netlink // A Socket is an operating-system specific implementation of netlink
@ -107,24 +97,40 @@ func (c *Conn) debug(fn func(d *debugger)) {
fn(c.d) fn(c.d)
} }
// Close closes the connection. // Close closes the connection. Close will unblock any concurrent calls to
// Receive which are waiting on a response from the kernel.
func (c *Conn) Close() error { func (c *Conn) Close() error {
return c.sock.Close() // Close does not acquire a lock because it must be able to interrupt any
// blocked system calls, such as when Receive is waiting on a multicast
// group message.
//
// We rely on the kernel to deal with concurrent operations to the netlink
// socket itself.
return newOpError("close", c.sock.Close())
} }
// Execute sends a single Message to netlink using Conn.Send, receives one or more // Execute sends a single Message to netlink using Send, receives one or more
// replies using Conn.Receive, and then checks the validity of the replies against // replies using Receive, and then checks the validity of the replies against
// the request using Validate. // the request using Validate.
// //
// See the documentation of Conn.Send, Conn.Receive, and Validate for details about // Execute acquires a lock for the duration of the function call which blocks
// concurrent calls to Send, SendMessages, and Receive, in order to ensure
// consistency between netlink request/reply messages.
//
// See the documentation of Send, Receive, and Validate for details about
// each function. // each function.
func (c *Conn) Execute(message Message) ([]Message, error) { func (c *Conn) Execute(message Message) ([]Message, error) {
req, err := c.Send(message) // Acquire the write lock and invoke the internal implementations of Send
// and Receive which require the lock already be held.
c.mu.Lock()
defer c.mu.Unlock()
req, err := c.lockedSend(message)
if err != nil { if err != nil {
return nil, err return nil, err
} }
replies, err := c.Receive() replies, err := c.lockedReceive()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -136,24 +142,14 @@ func (c *Conn) Execute(message Message) ([]Message, error) {
return replies, nil return replies, nil
} }
func (c *Conn) fixMsg(m *Message, ml int) {
if m.Header.Length == 0 {
m.Header.Length = uint32(nlmsgAlign(ml))
}
if m.Header.Sequence == 0 {
m.Header.Sequence = c.nextSequence()
}
if m.Header.PID == 0 {
m.Header.PID = c.pid
}
}
// SendMessages sends multiple Messages to netlink. The handling of // SendMessages sends multiple Messages to netlink. The handling of
// a Header's Length, Sequence and PID fields is the same as when // a Header's Length, Sequence and PID fields is the same as when
// calling Send. // calling Send.
func (c *Conn) SendMessages(messages []Message) ([]Message, error) { func (c *Conn) SendMessages(messages []Message) ([]Message, error) {
// Wait for any concurrent calls to Execute to finish before proceeding.
c.mu.RLock()
defer c.mu.RUnlock()
for idx, m := range messages { for idx, m := range messages {
ml := nlmsgLength(len(m.Data)) ml := nlmsgLength(len(m.Data))
@ -176,7 +172,7 @@ func (c *Conn) SendMessages(messages []Message) ([]Message, error) {
d.debugf(1, "send msgs: err: %v", err) d.debugf(1, "send msgs: err: %v", err)
}) })
return nil, err return nil, newOpError("send-messages", err)
} }
return messages, nil return messages, nil
@ -196,6 +192,17 @@ func (c *Conn) SendMessages(messages []Message) ([]Message, error) {
// If Header.PID is 0, it will be automatically populated using a PID // If Header.PID is 0, it will be automatically populated using a PID
// assigned by netlink. // assigned by netlink.
func (c *Conn) Send(message Message) (Message, error) { func (c *Conn) Send(message Message) (Message, error) {
// Wait for any concurrent calls to Execute to finish before proceeding.
c.mu.RLock()
defer c.mu.RUnlock()
return c.lockedSend(message)
}
// lockedSend implements Send, but must be called with c.mu acquired for reading.
// We rely on the kernel to deal with concurrent reads and writes to the netlink
// socket itself.
func (c *Conn) lockedSend(message Message) (Message, error) {
ml := nlmsgLength(len(message.Data)) ml := nlmsgLength(len(message.Data))
// TODO(mdlayher): fine-tune this limit. // TODO(mdlayher): fine-tune this limit.
@ -214,7 +221,7 @@ func (c *Conn) Send(message Message) (Message, error) {
d.debugf(1, "send: err: %v", err) d.debugf(1, "send: err: %v", err)
}) })
return Message{}, err return Message{}, newOpError("send", err)
} }
return message, nil return message, nil
@ -226,6 +233,17 @@ func (c *Conn) Send(message Message) (Message, error) {
// //
// If any of the messages indicate a netlink error, that error will be returned. // If any of the messages indicate a netlink error, that error will be returned.
func (c *Conn) Receive() ([]Message, error) { func (c *Conn) Receive() ([]Message, error) {
// Wait for any concurrent calls to Execute to finish before proceeding.
c.mu.RLock()
defer c.mu.RUnlock()
return c.lockedReceive()
}
// lockedReceive implements Receive, but must be called with c.mu acquired for reading.
// We rely on the kernel to deal with concurrent reads and writes to the netlink
// socket itself.
func (c *Conn) lockedReceive() ([]Message, error) {
msgs, err := c.receive() msgs, err := c.receive()
if err != nil { if err != nil {
c.debug(func(d *debugger) { c.debug(func(d *debugger) {
@ -248,7 +266,7 @@ func (c *Conn) Receive() ([]Message, error) {
// Trim the final message with multi-part done indicator if // Trim the final message with multi-part done indicator if
// present. // present.
if m := msgs[len(msgs)-1]; m.Header.Flags&HeaderFlagsMulti != 0 && m.Header.Type == HeaderTypeDone { if m := msgs[len(msgs)-1]; m.Header.Flags&Multi != 0 && m.Header.Type == Done {
return msgs[:len(msgs)-1], nil return msgs[:len(msgs)-1], nil
} }
@ -258,11 +276,18 @@ func (c *Conn) Receive() ([]Message, error) {
// receive is the internal implementation of Conn.Receive, which can be called // receive is the internal implementation of Conn.Receive, which can be called
// recursively to handle multi-part messages. // recursively to handle multi-part messages.
func (c *Conn) receive() ([]Message, error) { func (c *Conn) receive() ([]Message, error) {
// NB: All non-nil errors returned from this function *must* be of type
// OpError in order to maintain the appropriate contract with callers of
// this package.
//
// This contract also applies to functions called within this function,
// such as checkMessage.
var res []Message var res []Message
for { for {
msgs, err := c.sock.Receive() msgs, err := c.sock.Receive()
if err != nil { if err != nil {
return nil, err return nil, newOpError("receive", err)
} }
// If this message is multi-part, we will need to perform an recursive call // If this message is multi-part, we will need to perform an recursive call
@ -275,14 +300,14 @@ func (c *Conn) receive() ([]Message, error) {
} }
// Does this message indicate a multi-part message? // Does this message indicate a multi-part message?
if m.Header.Flags&HeaderFlagsMulti == 0 { if m.Header.Flags&Multi == 0 {
// No, check the next messages. // No, check the next messages.
continue continue
} }
// Does this message indicate the last message in a series of // Does this message indicate the last message in a series of
// multi-part messages from a single read? // multi-part messages from a single read?
multi = m.Header.Type != HeaderTypeDone multi = m.Header.Type != Done
} }
res = append(res, msgs...) res = append(res, msgs...)
@ -294,51 +319,6 @@ func (c *Conn) receive() ([]Message, error) {
} }
} }
// An fder is a Socket that supports retrieving its raw file descriptor.
type fder interface {
Socket
FD() int
}
var _ io.ReadWriteCloser = &fileReadWriteCloser{}
// A fileReadWriteCloser is a limited *os.File which only allows access to its
// Read and Write methods.
type fileReadWriteCloser struct {
f *os.File
}
// Read implements io.ReadWriteCloser.
func (rwc *fileReadWriteCloser) Read(b []byte) (int, error) { return rwc.f.Read(b) }
// Write implements io.ReadWriteCloser.
func (rwc *fileReadWriteCloser) Write(b []byte) (int, error) { return rwc.f.Write(b) }
// Close implements io.ReadWriteCloser.
func (rwc *fileReadWriteCloser) Close() error { return rwc.f.Close() }
// ReadWriteCloser returns a raw io.ReadWriteCloser backed by the connection
// of the Conn.
//
// ReadWriteCloser is intended for advanced use cases, such as those that do
// not involve standard netlink message passing.
//
// Once invoked, it is the caller's responsibility to ensure that operations
// performed using Conn and the raw io.ReadWriteCloser do not conflict with
// each other. In almost all scenarios, only one of the two should be used.
func (c *Conn) ReadWriteCloser() (io.ReadWriteCloser, error) {
fc, ok := c.sock.(fder)
if !ok {
return nil, errReadWriteCloserNotSupported
}
return &fileReadWriteCloser{
// Backing the io.ReadWriteCloser with an *os.File enables easy reading
// and writing without more system call boilerplate.
f: os.NewFile(uintptr(fc.FD()), "netlink"),
}, nil
}
// A groupJoinLeaver is a Socket that supports joining and leaving // A groupJoinLeaver is a Socket that supports joining and leaving
// netlink multicast groups. // netlink multicast groups.
type groupJoinLeaver interface { type groupJoinLeaver interface {
@ -349,22 +329,22 @@ type groupJoinLeaver interface {
// JoinGroup joins a netlink multicast group by its ID. // JoinGroup joins a netlink multicast group by its ID.
func (c *Conn) JoinGroup(group uint32) error { func (c *Conn) JoinGroup(group uint32) error {
gc, ok := c.sock.(groupJoinLeaver) conn, ok := c.sock.(groupJoinLeaver)
if !ok { if !ok {
return errMulticastGroupsNotSupported return notSupported("join-group")
} }
return gc.JoinGroup(group) return newOpError("join-group", conn.JoinGroup(group))
} }
// LeaveGroup leaves a netlink multicast group by its ID. // LeaveGroup leaves a netlink multicast group by its ID.
func (c *Conn) LeaveGroup(group uint32) error { func (c *Conn) LeaveGroup(group uint32) error {
gc, ok := c.sock.(groupJoinLeaver) conn, ok := c.sock.(groupJoinLeaver)
if !ok { if !ok {
return errMulticastGroupsNotSupported return notSupported("leave-group")
} }
return gc.LeaveGroup(group) return newOpError("leave-group", conn.LeaveGroup(group))
} }
// A bpfSetter is a Socket that supports setting and removing BPF filters. // A bpfSetter is a Socket that supports setting and removing BPF filters.
@ -376,22 +356,69 @@ type bpfSetter interface {
// SetBPF attaches an assembled BPF program to a Conn. // SetBPF attaches an assembled BPF program to a Conn.
func (c *Conn) SetBPF(filter []bpf.RawInstruction) error { func (c *Conn) SetBPF(filter []bpf.RawInstruction) error {
bc, ok := c.sock.(bpfSetter) conn, ok := c.sock.(bpfSetter)
if !ok { if !ok {
return errBPFFiltersNotSupported return notSupported("set-bpf")
} }
return bc.SetBPF(filter) return newOpError("set-bpf", conn.SetBPF(filter))
} }
// RemoveBPF removes a BPF filter from a Conn. // RemoveBPF removes a BPF filter from a Conn.
func (c *Conn) RemoveBPF() error { func (c *Conn) RemoveBPF() error {
s, ok := c.sock.(bpfSetter) conn, ok := c.sock.(bpfSetter)
if !ok { if !ok {
return errBPFFiltersNotSupported return notSupported("remove-bpf")
} }
return s.RemoveBPF() return newOpError("remove-bpf", conn.RemoveBPF())
}
// A deadlineSetter is a Socket that supports setting deadlines.
type deadlineSetter interface {
Socket
SetDeadline(time.Time) error
SetReadDeadline(time.Time) error
SetWriteDeadline(time.Time) error
}
// SetDeadline sets the read and write deadlines associated with the connection.
//
// Deadline functionality is only supported on Go 1.12+. Calling this function
// on older versions of Go will result in an error.
func (c *Conn) SetDeadline(t time.Time) error {
conn, ok := c.sock.(deadlineSetter)
if !ok {
return notSupported("set-deadline")
}
return newOpError("set-deadline", conn.SetDeadline(t))
}
// SetReadDeadline sets the read deadline associated with the connection.
//
// Deadline functionality is only supported on Go 1.12+. Calling this function
// on older versions of Go will result in an error.
func (c *Conn) SetReadDeadline(t time.Time) error {
conn, ok := c.sock.(deadlineSetter)
if !ok {
return notSupported("set-read-deadline")
}
return newOpError("set-read-deadline", conn.SetReadDeadline(t))
}
// SetWriteDeadline sets the write deadline associated with the connection.
//
// Deadline functionality is only supported on Go 1.12+. Calling this function
// on older versions of Go will result in an error.
func (c *Conn) SetWriteDeadline(t time.Time) error {
conn, ok := c.sock.(deadlineSetter)
if !ok {
return notSupported("set-write-deadline")
}
return newOpError("set-write-deadline", conn.SetWriteDeadline(t))
} }
// A ConnOption is a boolean option that may be set for a Conn. // A ConnOption is a boolean option that may be set for a Conn.
@ -405,6 +432,7 @@ const (
NoENOBUFS NoENOBUFS
ListenAllNSID ListenAllNSID
CapAcknowledge CapAcknowledge
ExtendedAcknowledge
) )
// An optionSetter is a Socket that supports setting netlink options. // An optionSetter is a Socket that supports setting netlink options.
@ -415,12 +443,12 @@ type optionSetter interface {
// SetOption enables or disables a netlink socket option for the Conn. // SetOption enables or disables a netlink socket option for the Conn.
func (c *Conn) SetOption(option ConnOption, enable bool) error { func (c *Conn) SetOption(option ConnOption, enable bool) error {
fc, ok := c.sock.(optionSetter) conn, ok := c.sock.(optionSetter)
if !ok { if !ok {
return errOptionsNotSupported return notSupported("set-option")
} }
return fc.SetOption(option, enable) return newOpError("set-option", conn.SetOption(option, enable))
} }
// A bufferSetter is a Socket that supports setting connection buffer sizes. // A bufferSetter is a Socket that supports setting connection buffer sizes.
@ -435,10 +463,10 @@ type bufferSetter interface {
func (c *Conn) SetReadBuffer(bytes int) error { func (c *Conn) SetReadBuffer(bytes int) error {
conn, ok := c.sock.(bufferSetter) conn, ok := c.sock.(bufferSetter)
if !ok { if !ok {
return errSetBufferNotSupported return notSupported("set-read-buffer")
} }
return conn.SetReadBuffer(bytes) return newOpError("set-read-buffer", conn.SetReadBuffer(bytes))
} }
// SetWriteBuffer sets the size of the operating system's transmit buffer // SetWriteBuffer sets the size of the operating system's transmit buffer
@ -446,10 +474,16 @@ func (c *Conn) SetReadBuffer(bytes int) error {
func (c *Conn) SetWriteBuffer(bytes int) error { func (c *Conn) SetWriteBuffer(bytes int) error {
conn, ok := c.sock.(bufferSetter) conn, ok := c.sock.(bufferSetter)
if !ok { if !ok {
return errSetBufferNotSupported return notSupported("set-write-buffer")
} }
return conn.SetWriteBuffer(bytes) return newOpError("set-write-buffer", conn.SetWriteBuffer(bytes))
}
// A filer is a Socket that supports retrieving its associated *os.File.
type filer interface {
Socket
File() *os.File
} }
var _ syscall.Conn = &Conn{} var _ syscall.Conn = &Conn{}
@ -460,8 +494,10 @@ var _ syscall.Conn = &Conn{}
// SyscallConn returns a raw network connection. This implements the // SyscallConn returns a raw network connection. This implements the
// syscall.Conn interface. // syscall.Conn interface.
// //
// Only the Control method of the returned syscall.RawConn is currently // On Go 1.12+, all methods of the returned syscall.RawConn are supported and
// implemented. // the Conn is integrated with the runtime network poller. On versions of Go
// prior to Go 1.12, only the Control method of the returned syscall.RawConn
// is implemented.
// //
// SyscallConn is intended for advanced use cases, such as getting and setting // SyscallConn is intended for advanced use cases, such as getting and setting
// arbitrary socket options using the netlink socket's file descriptor. // arbitrary socket options using the netlink socket's file descriptor.
@ -470,33 +506,29 @@ var _ syscall.Conn = &Conn{}
// performed using Conn and the syscall.RawConn do not conflict with // performed using Conn and the syscall.RawConn do not conflict with
// each other. // each other.
func (c *Conn) SyscallConn() (syscall.RawConn, error) { func (c *Conn) SyscallConn() (syscall.RawConn, error) {
conn, ok := c.sock.(fder) fc, ok := c.sock.(filer)
if !ok { if !ok {
return nil, errSyscallConnNotSupported return nil, notSupported("syscall-conn")
} }
return &rawConn{ return newRawConn(fc.File())
fd: uintptr(conn.FD()),
}, nil
} }
var _ syscall.RawConn = &rawConn{} // fixMsg updates the fields of m using the logic specified in Send.
func (c *Conn) fixMsg(m *Message, ml int) {
if m.Header.Length == 0 {
m.Header.Length = uint32(nlmsgAlign(ml))
}
// A rawConn is a syscall.RawConn. if m.Header.Sequence == 0 {
type rawConn struct { m.Header.Sequence = c.nextSequence()
fd uintptr }
if m.Header.PID == 0 {
m.Header.PID = c.pid
}
} }
func (rc *rawConn) Control(f func(fd uintptr)) error {
f(rc.fd)
return nil
}
// TODO(mdlayher): implement Read and Write?
func (rc *rawConn) Read(_ func(fd uintptr) (done bool)) error { return errSyscallConnNotSupported }
func (rc *rawConn) Write(_ func(fd uintptr) (done bool)) error { return errSyscallConnNotSupported }
// nextSequence atomically increments Conn's sequence number and returns // nextSequence atomically increments Conn's sequence number and returns
// the incremented value. // the incremented value.
func (c *Conn) nextSequence() uint32 { func (c *Conn) nextSequence() uint32 {
@ -511,7 +543,7 @@ func Validate(request Message, replies []Message) error {
// - request had no sequence, meaning we are probably validating // - request had no sequence, meaning we are probably validating
// a multicast reply // a multicast reply
if m.Header.Sequence != request.Header.Sequence && request.Header.Sequence != 0 { if m.Header.Sequence != request.Header.Sequence && request.Header.Sequence != 0 {
return errMismatchedSequence return newOpError("validate", errMismatchedSequence)
} }
// Check for mismatched PID, unless: // Check for mismatched PID, unless:
@ -520,7 +552,7 @@ func Validate(request Message, replies []Message) error {
// - netlink has not yet assigned us a PID // - netlink has not yet assigned us a PID
// - response had no PID, meaning it's from the kernel as a multicast reply // - response had no PID, meaning it's from the kernel as a multicast reply
if m.Header.PID != request.Header.PID && request.Header.PID != 0 && m.Header.PID != 0 { if m.Header.PID != request.Header.PID && request.Header.PID != 0 && m.Header.PID != 0 {
return errMismatchedPID return newOpError("validate", errMismatchedPID)
} }
} }
@ -533,7 +565,22 @@ type Config struct {
// no multicast group subscriptions will be made. // no multicast group subscriptions will be made.
Groups uint32 Groups uint32
// Network namespace the Conn needs to operate in. If set to 0, // NetNS specifies the network namespace the Conn will operate in.
// no network namespace will be entered. //
// If set (non-zero), Conn will enter the specified network namespace and
// an error will occur in Dial if the operation fails.
//
// If not set (zero), a best-effort attempt will be made to enter the
// network namespace of the calling thread: this means that any changes made
// to the calling thread's network namespace will also be reflected in Conn.
// If this operation fails (due to lack of permissions or because network
// namespaces are disabled by kernel configuration), Dial will not return
// an error, and the Conn will operate in the default network namespace of
// the process. This enables non-privileged use of Conn in applications
// which do not require elevated privileges.
//
// Entering a network namespace is a privileged operation (root or
// CAP_SYS_ADMIN are required), and most applications should leave this set
// to 0.
NetNS int NetNS int
} }

View file

@ -3,25 +3,26 @@
package netlink package netlink
import ( import (
"errors" "math"
"os" "os"
"runtime" "runtime"
"sync" "sync"
"syscall" "syscall"
"time"
"unsafe" "unsafe"
"golang.org/x/net/bpf" "golang.org/x/net/bpf"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
var (
errInvalidSockaddr = errors.New("expected unix.SockaddrNetlink but received different unix.Sockaddr")
errInvalidFamily = errors.New("received invalid netlink family")
)
var _ Socket = &conn{} var _ Socket = &conn{}
var _ deadlineSetter = &conn{}
// A conn is the Linux implementation of a netlink sockets connection. // A conn is the Linux implementation of a netlink sockets connection.
//
// All conn methods must wrap system call errors with os.NewSyscallError to
// enable more intelligible error messages in OpError.
type conn struct { type conn struct {
s socket s socket
sa *unix.SockaddrNetlink sa *unix.SockaddrNetlink
@ -32,10 +33,15 @@ type socket interface {
Bind(sa unix.Sockaddr) error Bind(sa unix.Sockaddr) error
Close() error Close() error
FD() int FD() int
File() *os.File
Getsockname() (unix.Sockaddr, error) Getsockname() (unix.Sockaddr, error)
Recvmsg(p, oob []byte, flags int) (n int, oobn int, recvflags int, from unix.Sockaddr, err error) Recvmsg(p, oob []byte, flags int) (n int, oobn int, recvflags int, from unix.Sockaddr, err error)
Sendmsg(p, oob []byte, to unix.Sockaddr, flags int) error Sendmsg(p, oob []byte, to unix.Sockaddr, flags int) error
SetSockopt(level, name int, v unsafe.Pointer, l uint32) error SetDeadline(t time.Time) error
SetReadDeadline(t time.Time) error
SetWriteDeadline(t time.Time) error
SetSockoptSockFprog(level, opt int, fprog *unix.SockFprog) error
SetSockoptInt(level, opt, value int) error
} }
// dial is the entry point for Dial. dial opens a netlink socket using // dial is the entry point for Dial. dial opens a netlink socket using
@ -56,7 +62,7 @@ func dial(family int, config *Config) (*conn, uint32, error) {
} }
if err := sock.Socket(family); err != nil { if err := sock.Socket(family); err != nil {
return nil, 0, err return nil, 0, os.NewSyscallError("socket", err)
} }
return bind(sock, config) return bind(sock, config)
@ -79,13 +85,13 @@ func bind(s socket, config *Config) (*conn, uint32, error) {
if err := s.Bind(addr); err != nil { if err := s.Bind(addr); err != nil {
_ = s.Close() _ = s.Close()
return nil, 0, err return nil, 0, os.NewSyscallError("bind", err)
} }
sa, err := s.Getsockname() sa, err := s.Getsockname()
if err != nil { if err != nil {
_ = s.Close() _ = s.Close()
return nil, 0, err return nil, 0, os.NewSyscallError("getsockname", err)
} }
pid := sa.(*unix.SockaddrNetlink).Pid pid := sa.(*unix.SockaddrNetlink).Pid
@ -112,7 +118,7 @@ func (c *conn) SendMessages(messages []Message) error {
Family: unix.AF_NETLINK, Family: unix.AF_NETLINK,
} }
return c.s.Sendmsg(buf, nil, addr, 0) return os.NewSyscallError("sendmsg", c.s.Sendmsg(buf, nil, addr, 0))
} }
// Send sends a single Message to netlink. // Send sends a single Message to netlink.
@ -126,7 +132,7 @@ func (c *conn) Send(m Message) error {
Family: unix.AF_NETLINK, Family: unix.AF_NETLINK,
} }
return c.s.Sendmsg(b, nil, addr, 0) return os.NewSyscallError("sendmsg", c.s.Sendmsg(b, nil, addr, 0))
} }
// Receive receives one or more Messages from netlink. // Receive receives one or more Messages from netlink.
@ -139,7 +145,7 @@ func (c *conn) Receive() ([]Message, error) {
// when PacketInfo ConnOption is true. // when PacketInfo ConnOption is true.
n, _, _, _, err := c.s.Recvmsg(b, nil, unix.MSG_PEEK) n, _, _, _, err := c.s.Recvmsg(b, nil, unix.MSG_PEEK)
if err != nil { if err != nil {
return nil, err return nil, os.NewSyscallError("recvmsg", err)
} }
// Break when we can read all messages // Break when we can read all messages
@ -152,17 +158,9 @@ func (c *conn) Receive() ([]Message, error) {
} }
// Read out all available messages // Read out all available messages
n, _, _, from, err := c.s.Recvmsg(b, nil, 0) n, _, _, _, err := c.s.Recvmsg(b, nil, 0)
if err != nil { if err != nil {
return nil, err return nil, os.NewSyscallError("recvmsg", err)
}
addr, ok := from.(*unix.SockaddrNetlink)
if !ok {
return nil, errInvalidSockaddr
}
if addr.Family != unix.AF_NETLINK {
return nil, errInvalidFamily
} }
n = nlmsgAlign(n) n = nlmsgAlign(n)
@ -187,7 +185,7 @@ func (c *conn) Receive() ([]Message, error) {
// Close closes the connection. // Close closes the connection.
func (c *conn) Close() error { func (c *conn) Close() error {
return c.s.Close() return os.NewSyscallError("close", c.s.Close())
} }
// FD retrieves the file descriptor of the Conn. // FD retrieves the file descriptor of the Conn.
@ -195,24 +193,27 @@ func (c *conn) FD() int {
return c.s.FD() return c.s.FD()
} }
// File retrieves the *os.File associated with the Conn.
func (c *conn) File() *os.File {
return c.s.File()
}
// JoinGroup joins a multicast group by ID. // JoinGroup joins a multicast group by ID.
func (c *conn) JoinGroup(group uint32) error { func (c *conn) JoinGroup(group uint32) error {
return c.s.SetSockopt( return os.NewSyscallError("setsockopt", c.s.SetSockoptInt(
unix.SOL_NETLINK, unix.SOL_NETLINK,
unix.NETLINK_ADD_MEMBERSHIP, unix.NETLINK_ADD_MEMBERSHIP,
unsafe.Pointer(&group), int(group),
uint32(unsafe.Sizeof(group)), ))
)
} }
// LeaveGroup leaves a multicast group by ID. // LeaveGroup leaves a multicast group by ID.
func (c *conn) LeaveGroup(group uint32) error { func (c *conn) LeaveGroup(group uint32) error {
return c.s.SetSockopt( return os.NewSyscallError("setsockopt", c.s.SetSockoptInt(
unix.SOL_NETLINK, unix.SOL_NETLINK,
unix.NETLINK_DROP_MEMBERSHIP, unix.NETLINK_DROP_MEMBERSHIP,
unsafe.Pointer(&group), int(group),
uint32(unsafe.Sizeof(group)), ))
)
} }
// SetBPF attaches an assembled BPF program to a conn. // SetBPF attaches an assembled BPF program to a conn.
@ -222,25 +223,21 @@ func (c *conn) SetBPF(filter []bpf.RawInstruction) error {
Filter: (*unix.SockFilter)(unsafe.Pointer(&filter[0])), Filter: (*unix.SockFilter)(unsafe.Pointer(&filter[0])),
} }
return c.s.SetSockopt( return os.NewSyscallError("setsockopt", c.s.SetSockoptSockFprog(
unix.SOL_SOCKET, unix.SOL_SOCKET,
unix.SO_ATTACH_FILTER, unix.SO_ATTACH_FILTER,
unsafe.Pointer(&prog), &prog,
uint32(unsafe.Sizeof(prog)), ))
)
} }
// RemoveBPF removes a BPF filter from a conn. // RemoveBPF removes a BPF filter from a conn.
func (c *conn) RemoveBPF() error { func (c *conn) RemoveBPF() error {
// dummy is ignored as argument to SO_DETACH_FILTER // 0 argument is ignored by SO_DETACH_FILTER.
// but SetSockopt requires it as an argument return os.NewSyscallError("setsockopt", c.s.SetSockoptInt(
var dummy uint32
return c.s.SetSockopt(
unix.SOL_SOCKET, unix.SOL_SOCKET,
unix.SO_DETACH_FILTER, unix.SO_DETACH_FILTER,
unsafe.Pointer(&dummy), 0,
uint32(unsafe.Sizeof(dummy)), ))
)
} }
// SetOption enables or disables a netlink socket option for the Conn. // SetOption enables or disables a netlink socket option for the Conn.
@ -248,46 +245,51 @@ func (c *conn) SetOption(option ConnOption, enable bool) error {
o, ok := linuxOption(option) o, ok := linuxOption(option)
if !ok { if !ok {
// Return the typical Linux error for an unknown ConnOption. // Return the typical Linux error for an unknown ConnOption.
return unix.ENOPROTOOPT return os.NewSyscallError("setsockopt", unix.ENOPROTOOPT)
} }
var v uint32 var v int
if enable { if enable {
v = 1 v = 1
} }
return c.s.SetSockopt( return os.NewSyscallError("setsockopt", c.s.SetSockoptInt(
unix.SOL_NETLINK, unix.SOL_NETLINK,
o, o,
unsafe.Pointer(&v), v,
uint32(unsafe.Sizeof(v)), ))
) }
func (c *conn) SetDeadline(t time.Time) error {
return c.s.SetDeadline(t)
}
func (c *conn) SetReadDeadline(t time.Time) error {
return c.s.SetReadDeadline(t)
}
func (c *conn) SetWriteDeadline(t time.Time) error {
return c.s.SetWriteDeadline(t)
} }
// SetReadBuffer sets the size of the operating system's receive buffer // SetReadBuffer sets the size of the operating system's receive buffer
// associated with the Conn. // associated with the Conn.
func (c *conn) SetReadBuffer(bytes int) error { func (c *conn) SetReadBuffer(bytes int) error {
v := uint32(bytes) return os.NewSyscallError("setsockopt", c.s.SetSockoptInt(
return c.s.SetSockopt(
unix.SOL_SOCKET, unix.SOL_SOCKET,
unix.SO_RCVBUF, unix.SO_RCVBUF,
unsafe.Pointer(&v), bytes,
uint32(unsafe.Sizeof(v)), ))
)
} }
// SetReadBuffer sets the size of the operating system's transmit buffer // SetReadBuffer sets the size of the operating system's transmit buffer
// associated with the Conn. // associated with the Conn.
func (c *conn) SetWriteBuffer(bytes int) error { func (c *conn) SetWriteBuffer(bytes int) error {
v := uint32(bytes) return os.NewSyscallError("setsockopt", c.s.SetSockoptInt(
return c.s.SetSockopt(
unix.SOL_SOCKET, unix.SOL_SOCKET,
unix.SO_SNDBUF, unix.SO_SNDBUF,
unsafe.Pointer(&v), bytes,
uint32(unsafe.Sizeof(v)), ))
)
} }
// linuxOption converts a ConnOption to its Linux value. // linuxOption converts a ConnOption to its Linux value.
@ -303,6 +305,8 @@ func linuxOption(o ConnOption) (int, bool) {
return unix.NETLINK_LISTEN_ALL_NSID, true return unix.NETLINK_LISTEN_ALL_NSID, true
case CapAcknowledge: case CapAcknowledge:
return unix.NETLINK_CAP_ACK, true return unix.NETLINK_CAP_ACK, true
case ExtendedAcknowledge:
return unix.NETLINK_EXT_ACK, true
default: default:
return 0, false return 0, false
} }
@ -325,122 +329,88 @@ var _ socket = &sysSocket{}
// A sysSocket is a socket which uses system calls for socket operations. // A sysSocket is a socket which uses system calls for socket operations.
type sysSocket struct { type sysSocket struct {
fd int mu sync.RWMutex
fd *os.File
wg *sync.WaitGroup closed bool
funcC chan<- func() g *lockedNetNSGoroutine
mu sync.RWMutex
done bool
doneC chan<- bool
} }
// newSysSocket creates a sysSocket that optionally locks its internal goroutine // newSysSocket creates a sysSocket that optionally locks its internal goroutine
// to a single thread. // to a single thread.
func newSysSocket(config *Config) (*sysSocket, error) { func newSysSocket(config *Config) (*sysSocket, error) {
var wg sync.WaitGroup // Determine network namespaces using the threadNetNS function.
wg.Add(1) g, err := newLockedNetNSGoroutine(config.NetNS, threadNetNS)
if err != nil {
// This system call loop strategy was inspired by:
// https://github.com/golang/go/wiki/LockOSThread. Thanks to squeed on
// Gophers Slack for providing this useful link.
funcC := make(chan func())
doneC := make(chan bool)
errC := make(chan error)
go func() {
// It is important to lock this goroutine to its OS thread for the duration
// of the netlink socket being used, or else the kernel may end up routing
// messages to the wrong places.
// See: http://lists.infradead.org/pipermail/libnl/2017-February/002293.html.
//
// The intent is to never unlock the OS thread, so that the thread
// will terminate when the goroutine exits starting in Go 1.10:
// https://go-review.googlesource.com/c/go/+/46038.
//
// However, due to recent instability and a potential bad interaction
// with the Go runtime for threads which are not unlocked, we have
// elected to temporarily unlock the thread when the goroutine terminates:
// https://github.com/golang/go/issues/25128#issuecomment-410764489.
runtime.LockOSThread()
defer runtime.UnlockOSThread()
defer wg.Done()
// The user requested the Conn to operate in a non-default network namespace.
if config.NetNS != 0 {
// Get the current namespace of the thread the goroutine is locked to.
origNetNS, err := getThreadNetNS()
if err != nil {
errC <- err
return
}
// Set the network namespace of the current thread using
// the file descriptor provided by the user.
err = setThreadNetNS(config.NetNS)
if err != nil {
errC <- err
return
}
// Once the thread's namespace has been successfully manipulated,
// make sure we change it back when the goroutine returns.
defer setThreadNetNS(origNetNS)
}
// Signal to caller that initialization was successful.
errC <- nil
for {
select {
case <-doneC:
return
case f := <-funcC:
f()
}
}
}()
// Wait for the goroutine to return err or nil.
if err := <-errC; err != nil {
return nil, err return nil, err
} }
return &sysSocket{ return &sysSocket{
wg: &wg, g: g,
funcC: funcC,
doneC: doneC,
}, nil }, nil
} }
// do runs f in a worker goroutine which can be locked to one thread. // do runs f in a worker goroutine which can be locked to one thread.
func (s *sysSocket) do(f func()) error { func (s *sysSocket) do(f func()) error {
done := make(chan bool, 1)
// All operations handled by this function are assumed to only // All operations handled by this function are assumed to only
// read from s.done. // read from s.done.
s.mu.RLock() s.mu.RLock()
defer s.mu.RUnlock()
if s.done { if s.closed {
s.mu.RUnlock()
return syscall.EBADF return syscall.EBADF
} }
s.funcC <- func() { s.g.run(f)
f()
done <- true
}
<-done
s.mu.RUnlock()
return nil return nil
} }
// read executes f, a read function, against the associated file descriptor.
func (s *sysSocket) read(f func(fd int) bool) error {
s.mu.RLock()
defer s.mu.RUnlock()
if s.closed {
return syscall.EBADF
}
var err error
s.g.run(func() {
err = fdread(s.fd, f)
})
return err
}
// write executes f, a write function, against the associated file descriptor.
func (s *sysSocket) write(f func(fd int) bool) error {
s.mu.RLock()
defer s.mu.RUnlock()
if s.closed {
return syscall.EBADF
}
var err error
s.g.run(func() {
err = fdwrite(s.fd, f)
})
return err
}
// control executes f, a control function, against the associated file descriptor.
func (s *sysSocket) control(f func(fd int)) error {
s.mu.RLock()
defer s.mu.RUnlock()
if s.closed {
return syscall.EBADF
}
var err error
s.g.run(func() {
err = fdcontrol(s.fd, f)
})
return err
}
func (s *sysSocket) Socket(family int) error { func (s *sysSocket) Socket(family int) error {
var ( var (
fd int fd int
@ -448,11 +418,47 @@ func (s *sysSocket) Socket(family int) error {
) )
doErr := s.do(func() { doErr := s.do(func() {
// Mirror what the standard library does when creating file
// descriptors: avoid racing a fork/exec with the creation
// of new file descriptors, so that child processes do not
// inherit netlink socket file descriptors unexpectedly.
//
// On Linux, SOCK_CLOEXEC was introduced in 2.6.27. OTOH,
// Go supports Linux 2.6.23 and above. If we get EINVAL on
// the first try, it may be that we are running on a kernel
// older than 2.6.27. In that case, take syscall.ForkLock
// and try again without SOCK_CLOEXEC.
//
// SOCK_NONBLOCK was also added in 2.6.27, but we don't
// use SOCK_NONBLOCK here for now, not until we remove support
// for Go 1.11, since we still support the old blocking file
// descriptor behavior.
//
// For a more thorough explanation, see similar work in the
// Go tree: func sysSocket in net/sock_cloexec.go, as well
// as the detailed comment in syscall/exec_unix.go.
//
// TODO(acln): update this to mirror net.sysSocket completely:
// use SOCK_NONBLOCK as well, and remove the separate
// setBlockingMode step once Go 1.11 support is removed and
// we switch to using entirely non-blocking file descriptors.
fd, err = unix.Socket( fd, err = unix.Socket(
unix.AF_NETLINK, unix.AF_NETLINK,
unix.SOCK_RAW, unix.SOCK_RAW|unix.SOCK_CLOEXEC,
family, family,
) )
if err == unix.EINVAL {
syscall.ForkLock.RLock()
fd, err = unix.Socket(
unix.AF_NETLINK,
unix.SOCK_RAW,
family,
)
if err == nil {
unix.CloseOnExec(fd)
}
syscall.ForkLock.RUnlock()
}
}) })
if doErr != nil { if doErr != nil {
return doErr return doErr
@ -461,14 +467,24 @@ func (s *sysSocket) Socket(family int) error {
return err return err
} }
s.fd = fd if err := setBlockingMode(fd); err != nil {
return err
}
// When using Go 1.12+, the setBlockingMode call we just did puts the
// file descriptor into non-blocking mode. In that case, os.NewFile
// registers the file descriptor with the runtime poller, which is
// then used for all subsequent operations.
//
// See also: https://golang.org/pkg/os/#NewFile
s.fd = os.NewFile(uintptr(fd), "netlink")
return nil return nil
} }
func (s *sysSocket) Bind(sa unix.Sockaddr) error { func (s *sysSocket) Bind(sa unix.Sockaddr) error {
var err error var err error
doErr := s.do(func() { doErr := s.control(func(fd int) {
err = unix.Bind(s.fd, sa) err = unix.Bind(fd, sa)
}) })
if doErr != nil { if doErr != nil {
return doErr return doErr
@ -478,7 +494,6 @@ func (s *sysSocket) Bind(sa unix.Sockaddr) error {
} }
func (s *sysSocket) Close() error { func (s *sysSocket) Close() error {
// Be sure to acquire a write lock because we need to stop any other // Be sure to acquire a write lock because we need to stop any other
// goroutines from sending system call requests after close. // goroutines from sending system call requests after close.
// Any invocation of do() after this write lock unlocks is guaranteed // Any invocation of do() after this write lock unlocks is guaranteed
@ -488,19 +503,18 @@ func (s *sysSocket) Close() error {
// Close the socket from the main thread, this operation has no risk // Close the socket from the main thread, this operation has no risk
// of routing data to the wrong socket. // of routing data to the wrong socket.
err := unix.Close(s.fd) err := s.fd.Close()
s.done = true s.closed = true
// Signal the syscall worker to exit, wait for the WaitGroup to join, // Stop the associated goroutine and wait for it to return.
// and close the job channel only when the worker is guaranteed to have stopped. s.g.stop()
close(s.doneC)
s.wg.Wait()
close(s.funcC)
return err return err
} }
func (s *sysSocket) FD() int { return s.fd } func (s *sysSocket) FD() int { return int(s.fd.Fd()) }
func (s *sysSocket) File() *os.File { return s.fd }
func (s *sysSocket) Getsockname() (unix.Sockaddr, error) { func (s *sysSocket) Getsockname() (unix.Sockaddr, error) {
var ( var (
@ -508,8 +522,8 @@ func (s *sysSocket) Getsockname() (unix.Sockaddr, error) {
err error err error
) )
doErr := s.do(func() { doErr := s.control(func(fd int) {
sa, err = unix.Getsockname(s.fd) sa, err = unix.Getsockname(fd)
}) })
if doErr != nil { if doErr != nil {
return nil, doErr return nil, doErr
@ -525,8 +539,16 @@ func (s *sysSocket) Recvmsg(p, oob []byte, flags int) (int, int, int, unix.Socka
err error err error
) )
doErr := s.do(func() { doErr := s.read(func(fd int) bool {
n, oobn, recvflags, from, err = unix.Recvmsg(s.fd, p, oob, flags) n, oobn, recvflags, from, err = unix.Recvmsg(fd, p, oob, flags)
// When the socket is in non-blocking mode, we might see
// EAGAIN and end up here. In that case, return false to
// let the poller wait for readiness. See the source code
// for internal/poll.FD.RawRead for more details.
//
// If the socket is in blocking mode, EAGAIN should never occur.
return err != syscall.EAGAIN
}) })
if doErr != nil { if doErr != nil {
return 0, 0, 0, nil, doErr return 0, 0, 0, nil, doErr
@ -537,8 +559,11 @@ func (s *sysSocket) Recvmsg(p, oob []byte, flags int) (int, int, int, unix.Socka
func (s *sysSocket) Sendmsg(p, oob []byte, to unix.Sockaddr, flags int) error { func (s *sysSocket) Sendmsg(p, oob []byte, to unix.Sockaddr, flags int) error {
var err error var err error
doErr := s.do(func() { doErr := s.write(func(fd int) bool {
err = unix.Sendmsg(s.fd, p, oob, to, flags) err = unix.Sendmsg(fd, p, oob, to, flags)
// Analogous to Recvmsg. See the comments there.
return err != syscall.EAGAIN
}) })
if doErr != nil { if doErr != nil {
return doErr return doErr
@ -547,10 +572,27 @@ func (s *sysSocket) Sendmsg(p, oob []byte, to unix.Sockaddr, flags int) error {
return err return err
} }
func (s *sysSocket) SetSockopt(level, name int, v unsafe.Pointer, l uint32) error { func (s *sysSocket) SetDeadline(t time.Time) error {
return s.fd.SetDeadline(t)
}
func (s *sysSocket) SetReadDeadline(t time.Time) error {
return s.fd.SetReadDeadline(t)
}
func (s *sysSocket) SetWriteDeadline(t time.Time) error {
return s.fd.SetWriteDeadline(t)
}
func (s *sysSocket) SetSockoptInt(level, opt, value int) error {
// Value must be in range of a C integer.
if value < math.MinInt32 || value > math.MaxInt32 {
return unix.EINVAL
}
var err error var err error
doErr := s.do(func() { doErr := s.control(func(fd int) {
err = setsockopt(s.fd, level, name, v, l) err = unix.SetsockoptInt(fd, level, opt, value)
}) })
if doErr != nil { if doErr != nil {
return doErr return doErr
@ -558,3 +600,142 @@ func (s *sysSocket) SetSockopt(level, name int, v unsafe.Pointer, l uint32) erro
return err return err
} }
func (s *sysSocket) SetSockoptSockFprog(level, opt int, fprog *unix.SockFprog) error {
var err error
doErr := s.control(func(fd int) {
err = unix.SetsockoptSockFprog(fd, level, opt, fprog)
})
if doErr != nil {
return doErr
}
return err
}
// lockedNetNSGoroutine is a worker goroutine locked to an operating system
// thread, optionally configured to run in a non-default network namespace.
type lockedNetNSGoroutine struct {
wg sync.WaitGroup
doneC chan struct{}
funcC chan func()
}
// newLockedNetNSGoroutine creates a lockedNetNSGoroutine that will enter the
// specified network namespace netNS (by file descriptor), and will use the
// getNS function to produce netNS handles.
func newLockedNetNSGoroutine(netNS int, getNS func() (*netNS, error)) (*lockedNetNSGoroutine, error) {
// Any bare syscall errors (e.g. setns) should be wrapped with
// os.NewSyscallError for the remainder of this function.
callerNS, err := getNS()
if err != nil {
return nil, err
}
defer callerNS.Close()
g := &lockedNetNSGoroutine{
doneC: make(chan struct{}),
funcC: make(chan func()),
}
errC := make(chan error)
g.wg.Add(1)
go func() {
// It is important to lock this goroutine to its OS thread for the duration
// of the netlink socket being used, or else the kernel may end up routing
// messages to the wrong places.
// See: http://lists.infradead.org/pipermail/libnl/2017-February/002293.html.
//
//
// In addition, the OS thread must also remain locked because we attempt
// to manipulate the network namespace of the thread within this goroutine.
//
// The intent is to never unlock the OS thread, so that the thread
// will terminate when the goroutine exits starting in Go 1.10:
// https://go-review.googlesource.com/c/go/+/46038.
//
// However, due to recent instability and a potential bad interaction
// with the Go runtime for threads which are not unlocked, we have
// elected to temporarily unlock the thread when the goroutine terminates:
// https://github.com/golang/go/issues/25128#issuecomment-410764489.
runtime.LockOSThread()
defer runtime.UnlockOSThread()
defer g.wg.Done()
// Get the current namespace of the thread the goroutine is locked to.
threadNS, err := getNS()
if err != nil {
errC <- err
return
}
defer threadNS.Close()
// Attempt to set the network namespace of the current thread to either:
// - the namespace referred to by the provided file descriptor from config
// - the calling thread's namespace
//
// See the rules specified in the Config.NetNS documentation.
explicitNS := true
if netNS == 0 {
explicitNS = false
netNS = int(callerNS.FD())
}
// Only return an error if the network namespace was explicitly
// configured; implicit configuration by zero value should be ignored.
err = threadNS.Set(netNS)
switch {
case err != nil && explicitNS:
errC <- err
return
case err == nil:
// If the thread's namespace has been successfully manipulated,
// make sure we change it back when the goroutine returns.
defer threadNS.Restore()
default:
// We couldn't successfully set the namespace, but the caller didn't
// explicitly ask for it to be set either. Continue.
}
// Signal to caller that initialization was successful.
errC <- nil
for {
select {
case <-g.doneC:
return
case f := <-g.funcC:
f()
}
}
}()
// Wait for the goroutine to return err or nil.
if err := <-errC; err != nil {
return nil, err
}
return g, nil
}
// stop signals the goroutine to stop and blocks until it does.
//
// It is invalid to call run concurrently with stop. It is also invalid to
// call run after stop has returned.
func (g *lockedNetNSGoroutine) stop() {
close(g.doneC)
g.wg.Wait()
}
// run runs f on the worker goroutine.
func (g *lockedNetNSGoroutine) run(f func()) {
done := make(chan struct{})
g.funcC <- func() {
defer close(done)
f()
}
<-done
}

View file

@ -7,12 +7,10 @@ import (
"runtime" "runtime"
) )
var ( // errUnimplemented is returned by all functions on platforms that
// errUnimplemented is returned by all functions on platforms that // cannot make use of netlink sockets.
// cannot make use of netlink sockets. var errUnimplemented = fmt.Errorf("netlink: not implemented on %s/%s",
errUnimplemented = fmt.Errorf("netlink: not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
runtime.GOOS, runtime.GOARCH)
)
var _ Socket = &conn{} var _ Socket = &conn{}

View file

@ -8,10 +8,8 @@ import (
"strings" "strings"
) )
var ( // Arguments used to create a debugger.
// Arguments used to create a debugger. var debugArgs []string
debugArgs []string
)
func init() { func init() {
// Is netlink debugging enabled? // Is netlink debugging enabled?

View file

@ -1,5 +1,17 @@
// Package netlink provides low-level access to Linux netlink sockets. // Package netlink provides low-level access to Linux netlink sockets.
// //
// If you have any questions or you'd like some guidance, please join us on
// Gophers Slack (https://invite.slack.golangbridge.org) in the #networking
// channel!
//
//
// Network namespaces
//
// This package is aware of Linux network namespaces, and can enter different
// network namespaces either implicitly or explicitly, depending on
// configuration. The Config structure passed to Dial to create a Conn controls
// these behaviors. See the documentation of Config.NetNS for details.
//
// //
// Debugging // Debugging
// //
@ -20,3 +32,5 @@
// //
// level=N: specify the debugging level (only "1" is currently supported) // level=N: specify the debugging level (only "1" is currently supported)
package netlink package netlink
//go:generate dot netlink.dot -T svg -o netlink.svg

119
vendor/github.com/mdlayher/netlink/errors.go generated vendored Normal file
View file

@ -0,0 +1,119 @@
package netlink
import (
"errors"
"fmt"
"net"
"os"
)
// Error messages which can be returned by Validate.
var (
errMismatchedSequence = errors.New("mismatched sequence in netlink reply")
errMismatchedPID = errors.New("mismatched PID in netlink reply")
errShortErrorMessage = errors.New("not enough data for netlink error code")
)
// Errors which can be returned by a Socket that does not implement
// all exposed methods of Conn.
var errNotSupported = errors.New("operation not supported")
// notSupported provides a concise constructor for "not supported" errors.
func notSupported(op string) error {
return newOpError(op, errNotSupported)
}
// IsNotExist determines if an error is produced as the result of querying some
// file, object, resource, etc. which does not exist. Users of this package
// should always use netlink.IsNotExist, rather than os.IsNotExist, when
// checking for specific netlink-related errors.
//
// Errors types created by this package, such as OpError, can be used with
// IsNotExist, but this function also defers to the behavior of os.IsNotExist
// for unrecognized error types.
func IsNotExist(err error) bool {
switch err := err.(type) {
case *OpError:
// TODO(mdlayher): more error handling logic?
// Unwrap the inner error and use the stdlib's logic.
return os.IsNotExist(err.Err)
default:
return os.IsNotExist(err)
}
}
var _ error = &OpError{}
var _ net.Error = &OpError{}
// An OpError is an error produced as the result of a failed netlink operation.
type OpError struct {
// Op is the operation which caused this OpError, such as "send"
// or "receive".
Op string
// Err is the underlying error which caused this OpError.
//
// If Err was produced by a system call error, Err will be of type
// *os.SyscallError. If Err was produced by an error code in a netlink
// message, Err will contain a raw error value type such as a unix.Errno.
//
// Most callers should inspect Err using a helper such as IsNotExist.
Err error
}
// newOpError is a small wrapper for creating an OpError. As a convenience, it
// returns nil if the input err is nil: akin to os.NewSyscallError.
func newOpError(op string, err error) error {
if err == nil {
return nil
}
return &OpError{
Op: op,
Err: err,
}
}
func (e *OpError) Error() string {
if e == nil {
return "<nil>"
}
return fmt.Sprintf("netlink %s: %v", e.Op, e.Err)
}
// Portions of this code taken from the Go standard library:
//
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
type timeout interface {
Timeout() bool
}
// Timeout reports whether the error was caused by an I/O timeout.
func (e *OpError) Timeout() bool {
if ne, ok := e.Err.(*os.SyscallError); ok {
t, ok := ne.Err.(timeout)
return ok && t.Timeout()
}
t, ok := e.Err.(timeout)
return ok && t.Timeout()
}
type temporary interface {
Temporary() bool
}
// Temporary reports whether an operation may succeed if retried.
func (e *OpError) Temporary() bool {
if ne, ok := e.Err.(*os.SyscallError); ok {
t, ok := ne.Err.(temporary)
return ok && t.Temporary()
}
t, ok := e.Err.(temporary)
return ok && t.Temporary()
}

44
vendor/github.com/mdlayher/netlink/fdcall_gteq_1.12.go generated vendored Normal file
View file

@ -0,0 +1,44 @@
//+build go1.12,linux
package netlink
import (
"os"
"golang.org/x/sys/unix"
)
// setBlockingMode puts the file descriptor into non-blocking mode.
func setBlockingMode(sysfd int) error {
return unix.SetNonblock(sysfd, true)
}
func fdread(fd *os.File, f func(int) (done bool)) error {
rc, err := fd.SyscallConn()
if err != nil {
return err
}
return rc.Read(func(sysfd uintptr) bool {
return f(int(sysfd))
})
}
func fdwrite(fd *os.File, f func(int) (done bool)) error {
rc, err := fd.SyscallConn()
if err != nil {
return err
}
return rc.Write(func(sysfd uintptr) bool {
return f(int(sysfd))
})
}
func fdcontrol(fd *os.File, f func(int)) error {
rc, err := fd.SyscallConn()
if err != nil {
return err
}
return rc.Control(func(sysfd uintptr) {
f(int(sysfd))
})
}

29
vendor/github.com/mdlayher/netlink/fdcall_lt_1.12.go generated vendored Normal file
View file

@ -0,0 +1,29 @@
//+build !go1.12,linux
package netlink
import "os"
// setBlockingMode exists for compatibility reasons: prior to Go 1.12,
// package netlink used blocking file descriptors, and did not support
// deadlines. This variant of setBlockingMode, which does nothing (i.e.
// it leaves the file descriptor in blocking mode), maintains compatibility
// for users up to and including Go 1.11.
func setBlockingMode(sysfd int) error {
return nil
}
func fdread(fd *os.File, f func(int) (done bool)) error {
f(int(fd.Fd()))
return nil
}
func fdwrite(fd *os.File, f func(int) (done bool)) error {
f(int(fd.Fd()))
return nil
}
func fdcontrol(fd *os.File, f func(int)) error {
f(int(fd.Fd()))
return nil
}

View file

@ -4,7 +4,7 @@ package netlink
func Fuzz(data []byte) int { func Fuzz(data []byte) int {
return fuzzAttributes(data) return fuzzAttributes(data)
//return fuzzMessage(data) // return fuzzMessage(data)
} }
func fuzzAttributes(data []byte) int { func fuzzAttributes(data []byte) int {

10
vendor/github.com/mdlayher/netlink/go.mod generated vendored Normal file
View file

@ -0,0 +1,10 @@
module github.com/mdlayher/netlink
go 1.12
require (
github.com/google/go-cmp v0.3.1
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456
)

16
vendor/github.com/mdlayher/netlink/go.sum generated vendored Normal file
View file

@ -0,0 +1,16 @@
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a h1:84IpUNXj4mCR9CuCEvSiCArMbzr/TMbuPIadKDwypkI=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View file

@ -21,61 +21,56 @@ type HeaderFlags uint16
const ( const (
// General netlink communication flags. // General netlink communication flags.
// HeaderFlagsRequest indicates a request to netlink. // Request indicates a request to netlink.
HeaderFlagsRequest HeaderFlags = 1 Request HeaderFlags = 1
// HeaderFlagsMulti indicates a multi-part message, terminated // Multi indicates a multi-part message, terminated by Done on the
// by HeaderTypeDone on the last message. // last message.
HeaderFlagsMulti HeaderFlags = 2 Multi HeaderFlags = 2
// HeaderFlagsAcknowledge requests that netlink reply with // Acknowledge requests that netlink reply with an acknowledgement
// an acknowledgement using HeaderTypeError and, if needed, // using Error and, if needed, an error code.
// an error code. Acknowledge HeaderFlags = 4
HeaderFlagsAcknowledge HeaderFlags = 4
// HeaderFlagsEcho requests that netlink echo this request // Echo requests that netlink echo this request back to the sender.
// back to the sender. Echo HeaderFlags = 8
HeaderFlagsEcho HeaderFlags = 8
// HeaderFlagsDumpInterrupted indicates that a dump was // DumpInterrupted indicates that a dump was inconsistent due to a
// inconsistent due to a sequence change. // sequence change.
HeaderFlagsDumpInterrupted HeaderFlags = 16 DumpInterrupted HeaderFlags = 16
// HeaderFlagsDumpFiltered indicates that a dump was filtered // DumpFiltered indicates that a dump was filtered as requested.
// as requested. DumpFiltered HeaderFlags = 32
HeaderFlagsDumpFiltered HeaderFlags = 32
// Flags used to retrieve data from netlink. // Flags used to retrieve data from netlink.
// HeaderFlagsRoot requests that netlink return a complete table instead // Root requests that netlink return a complete table instead of a
// of a single entry. // single entry.
HeaderFlagsRoot HeaderFlags = 0x100 Root HeaderFlags = 0x100
// HeaderFlagsMatch requests that netlink return a list of all matching // Match requests that netlink return a list of all matching entries.
// entries. Match HeaderFlags = 0x200
HeaderFlagsMatch HeaderFlags = 0x200
// HeaderFlagsAtomic requests that netlink send an atomic snapshot of // Atomic requests that netlink send an atomic snapshot of its entries.
// its entries. Requires CAP_NET_ADMIN or an effective UID of 0. // Requires CAP_NET_ADMIN or an effective UID of 0.
HeaderFlagsAtomic HeaderFlags = 0x400 Atomic HeaderFlags = 0x400
// HeaderFlagsDump requests that netlink return a complete list of // Dump requests that netlink return a complete list of all entries.
// all entries. Dump HeaderFlags = Root | Match
HeaderFlagsDump HeaderFlags = HeaderFlagsRoot | HeaderFlagsMatch
// Flags used to create objects. // Flags used to create objects.
// HeaderFlagsReplace indicates request replaces an existing matching object. // Replace indicates request replaces an existing matching object.
HeaderFlagsReplace HeaderFlags = 0x100 Replace HeaderFlags = 0x100
// HeaderFlagsExcl indicates request does not replace the object if it already exists. // Excl indicates request does not replace the object if it already exists.
HeaderFlagsExcl HeaderFlags = 0x200 Excl HeaderFlags = 0x200
// HeaderFlagsCreate indicates request creates an object if it doesn't already exist. // Create indicates request creates an object if it doesn't already exist.
HeaderFlagsCreate HeaderFlags = 0x400 Create HeaderFlags = 0x400
// HeaderFlagsAppend indicates request adds to the end of the object list. // Append indicates request adds to the end of the object list.
HeaderFlagsAppend HeaderFlags = 0x800 Append HeaderFlags = 0x800
) )
// String returns the string representation of a HeaderFlags. // String returns the string representation of a HeaderFlags.
@ -123,30 +118,30 @@ func (f HeaderFlags) String() string {
type HeaderType uint16 type HeaderType uint16
const ( const (
// HeaderTypeNoop indicates that no action was taken. // Noop indicates that no action was taken.
HeaderTypeNoop HeaderType = 0x1 Noop HeaderType = 0x1
// HeaderTypeError indicates an error code is present, which is also // Error indicates an error code is present, which is also used to indicate
// used to indicate success when the code is 0. // success when the code is 0.
HeaderTypeError HeaderType = 0x2 Error HeaderType = 0x2
// HeaderTypeDone indicates the end of a multi-part message. // Done indicates the end of a multi-part message.
HeaderTypeDone HeaderType = 0x3 Done HeaderType = 0x3
// HeaderTypeOverrun indicates that data was lost from this message. // Overrun indicates that data was lost from this message.
HeaderTypeOverrun HeaderType = 0x4 Overrun HeaderType = 0x4
) )
// String returns the string representation of a HeaderType. // String returns the string representation of a HeaderType.
func (t HeaderType) String() string { func (t HeaderType) String() string {
switch t { switch t {
case HeaderTypeNoop: case Noop:
return "noop" return "noop"
case HeaderTypeError: case Error:
return "error" return "error"
case HeaderTypeDone: case Done:
return "done" return "done"
case HeaderTypeOverrun: case Overrun:
return "overrun" return "overrun"
default: default:
return fmt.Sprintf("unknown(%d)", t) return fmt.Sprintf("unknown(%d)", t)
@ -231,6 +226,10 @@ func (m *Message) UnmarshalBinary(b []byte) error {
// checkMessage checks a single Message for netlink errors. // checkMessage checks a single Message for netlink errors.
func checkMessage(m Message) error { func checkMessage(m Message) error {
// NB: All non-nil errors returned from this function *must* be of type
// OpError in order to maintain the appropriate contract with callers of
// this package.
const success = 0 const success = 0
// Per libnl documentation, only messages that indicate type error can // Per libnl documentation, only messages that indicate type error can
@ -242,18 +241,19 @@ func checkMessage(m Message) error {
// it is unknown whether this change was correct or not. If you run into // it is unknown whether this change was correct or not. If you run into
// a problem with your application because of this change, please file // a problem with your application because of this change, please file
// an issue. // an issue.
if m.Header.Type != HeaderTypeError { if m.Header.Type != Error {
return nil return nil
} }
if len(m.Data) < 4 { if len(m.Data) < 4 {
return errShortErrorMessage return newOpError("receive", errShortErrorMessage)
} }
if c := nlenc.Int32(m.Data[0:4]); c != success { if c := nlenc.Int32(m.Data[0:4]); c != success {
// Error code is a negative integer, convert it into // Error code is a negative integer, convert it into an OS-specific raw
// an OS-specific system call error // system call error, but do not wrap with os.NewSyscallError to signify
return newError(-1 * int(c)) // that this error was produced by a netlink message; not a system call.
return newOpError("receive", newError(-1*int(c)))
} }
return nil return nil

86
vendor/github.com/mdlayher/netlink/netlink.dot generated vendored Normal file
View file

@ -0,0 +1,86 @@
digraph {
rankdir = LR
subgraph cluster_netlink {
"github.com/mdlayher/netlink" [URL="https://github.com/mdlayher/netlink"]
}
subgraph cluster_connector {
label = "NETLINK_CONNECTOR";
{
"github.com/fearful-symmetry/garlic" [URL="https://github.com/fearful-symmetry/garlic"]
} -> "github.com/mdlayher/netlink"
}
subgraph cluster_crypto {
label = "NETLINK_CRYPTO";
{
"github.com/mdlayher/cryptonl" [URL="https://github.com/mdlayher/cryptonl"]
} -> "github.com/mdlayher/netlink"
}
subgraph cluster_generic {
label = "NETLINK_GENERIC (genetlink)";
"github.com/mdlayher/genetlink" [URL="https://github.com/mdlayher/genetlink"]
"github.com/mdlayher/genetlink" -> "github.com/mdlayher/netlink"
{
"github.com/axatrax/l2tp" [URL="https://github.com/axatrax/l2tp"]
"github.com/digitalocean/go-openvswitch" [URL="https://github.com/digitalocean/go-openvswitch"]
"github.com/mdlayher/devlink" [URL="https://github.com/mdlayher/devlink"]
"github.com/mdlayher/quota" [URL="https://github.com/mdlayher/quota"]
"github.com/mdlayher/taskstats" [URL="https://github.com/mdlayher/taskstats"]
"github.com/mdlayher/wifi" [URL="https://github.com/mdlayher/wifi"]
"github.com/Merovius/nbd" [URL="https://github.com/Merovius/nbd"]
"github.com/rtr7/router7" [URL="https://github.com/rtr7/router7"]
"github.com/u-root/u-bmc" [URL="https://github.com/u-root/u-bmc"]
"golang.zx2c4.com/wireguard/wgctrl" [URL="https://golang.zx2c4.com/wireguard/wgctrl"]
} -> "github.com/mdlayher/genetlink"
}
subgraph cluster_kobject_uevent {
label = "NETLINK_KOBJECT_UEVENT";
{
"github.com/mdlayher/kobject" [URL="https://github.com/mdlayher/kobject"]
} -> "github.com/mdlayher/netlink"
}
subgraph cluster_netfilter {
label = "NETLINK_NETFILTER (nfnetlink)";
{
"github.com/florianl/go-conntrack" [URL="https://github.com/florianl/go-conntrack"]
"github.com/florianl/go-nflog" [URL="https://github.com/florianl/go-nflog"]
"github.com/florianl/go-nfqueue" [URL="https://github.com/florianl/go-nfqueue"]
"github.com/google/nftables" [URL="https://github.com/google/nftables"]
"github.com/ti-mo/netfilter" [URL="https://github.com/ti-mo/netfilter"]
} -> "github.com/mdlayher/netlink"
{
"github.com/ti-mo/conntrack" [URL="https://github.com/ti-mo/conntrack"]
} -> "github.com/ti-mo/netfilter"
}
subgraph cluster_route {
label = "NETLINK_ROUTE (rtnetlink)";
{
"github.com/ema/qdisc" [URL="https://github.com/ema/qdisc"]
"github.com/florianl/go-tc" [URL="https://github.com/florianl/go-tc"]
"github.com/jsimonetti/rtnetlink" [URL="https://github.com/jsimonetti/rtnetlink"]
"gitlab.com/mergetb/tech/rtnl" [URL="https://gitlab.com/mergetb/tech/rtnl"]
} -> "github.com/mdlayher/netlink"
}
subgraph cluster_w1 {
label = "NETLINK_W1";
{
"github.com/SpComb/go-onewire" [URL="https://github.com/SpComb/go-onewire"]
} -> "github.com/mdlayher/netlink"
}
}

436
vendor/github.com/mdlayher/netlink/netlink.svg generated vendored Normal file
View file

@ -0,0 +1,436 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
-->
<!-- Title: %3 Pages: 1 -->
<svg width="928pt" height="1461pt"
viewBox="0.00 0.00 928.33 1461.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1457)">
<title>%3</title>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-1457 924.3276,-1457 924.3276,4 -4,4"/>
<g id="clust1" class="cluster">
<title>cluster_netlink</title>
<polygon fill="none" stroke="#000000" points="667.5479,-417 667.5479,-469 912.3276,-469 912.3276,-417 667.5479,-417"/>
</g>
<g id="clust2" class="cluster">
<title>cluster_connector</title>
<polygon fill="none" stroke="#000000" points="354.6724,-1370 354.6724,-1445 647.5479,-1445 647.5479,-1370 354.6724,-1370"/>
<text text-anchor="middle" x="501.1102" y="-1429.8" font-family="Times,serif" font-size="14.00" fill="#000000">NETLINK_CONNECTOR</text>
</g>
<g id="clust4" class="cluster">
<title>cluster_crypto</title>
<polygon fill="none" stroke="#000000" points="374.1707,-1287 374.1707,-1362 628.0496,-1362 628.0496,-1287 374.1707,-1287"/>
<text text-anchor="middle" x="501.1102" y="-1346.8" font-family="Times,serif" font-size="14.00" fill="#000000">NETLINK_CRYPTO</text>
</g>
<g id="clust6" class="cluster">
<title>cluster_generic</title>
<polygon fill="none" stroke="#000000" points="8,-718 8,-1279 631.2993,-1279 631.2993,-718 8,-718"/>
<text text-anchor="middle" x="319.6497" y="-1263.8" font-family="Times,serif" font-size="14.00" fill="#000000">NETLINK_GENERIC (genetlink)</text>
</g>
<g id="clust8" class="cluster">
<title>cluster_kobject_uevent</title>
<polygon fill="none" stroke="#000000" points="377.4204,-635 377.4204,-710 624.7999,-710 624.7999,-635 377.4204,-635"/>
<text text-anchor="middle" x="501.1102" y="-694.8" font-family="Times,serif" font-size="14.00" fill="#000000">NETLINK_KOBJECT_UEVENT</text>
</g>
<g id="clust10" class="cluster">
<title>cluster_netfilter</title>
<polygon fill="none" stroke="#000000" points="35.2976,-336 35.2976,-627 612.451,-627 612.451,-336 35.2976,-336"/>
<text text-anchor="middle" x="323.8743" y="-611.8" font-family="Times,serif" font-size="14.00" fill="#000000">NETLINK_NETFILTER (nfnetlink)</text>
</g>
<g id="clust13" class="cluster">
<title>cluster_route</title>
<polygon fill="none" stroke="#000000" points="371.5709,-91 371.5709,-328 630.6494,-328 630.6494,-91 371.5709,-91"/>
<text text-anchor="middle" x="501.1102" y="-312.8" font-family="Times,serif" font-size="14.00" fill="#000000">NETLINK_ROUTE (rtnetlink)</text>
</g>
<g id="clust15" class="cluster">
<title>cluster_w1</title>
<polygon fill="none" stroke="#000000" points="365.7215,-8 365.7215,-83 636.4988,-83 636.4988,-8 365.7215,-8"/>
<text text-anchor="middle" x="501.1102" y="-67.8" font-family="Times,serif" font-size="14.00" fill="#000000">NETLINK_W1</text>
</g>
<!-- github.com/mdlayher/netlink -->
<g id="node1" class="node">
<title>github.com/mdlayher/netlink</title>
<g id="a_node1"><a xlink:href="https://github.com/mdlayher/netlink" xlink:title="github.com/mdlayher/netlink">
<ellipse fill="none" stroke="#000000" cx="789.9377" cy="-443" rx="114.2798" ry="18"/>
<text text-anchor="middle" x="789.9377" y="-439.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/mdlayher/netlink</text>
</a>
</g>
</g>
<!-- github.com/fearful&#45;symmetry/garlic -->
<g id="node2" class="node">
<title>github.com/fearful&#45;symmetry/garlic</title>
<g id="a_node2"><a xlink:href="https://github.com/fearful-symmetry/garlic" xlink:title="github.com/fearful&#45;symmetry/garlic">
<ellipse fill="none" stroke="#000000" cx="501.1102" cy="-1396" rx="138.3755" ry="18"/>
<text text-anchor="middle" x="501.1102" y="-1392.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/fearful&#45;symmetry/garlic</text>
</a>
</g>
</g>
<!-- github.com/fearful&#45;symmetry/garlic&#45;&gt;github.com/mdlayher/netlink -->
<g id="edge1" class="edge">
<title>github.com/fearful&#45;symmetry/garlic&#45;&gt;github.com/mdlayher/netlink</title>
<path fill="none" stroke="#000000" d="M618.0901,-1386.1685C629.0968,-1381.2937 639.2266,-1374.7394 647.5479,-1366 711.2893,-1299.0557 774.4581,-618.9655 787.4947,-471.2237"/>
<polygon fill="#000000" stroke="#000000" points="790.9911,-471.4178 788.3785,-461.1501 784.0178,-470.8059 790.9911,-471.4178"/>
</g>
<!-- github.com/mdlayher/cryptonl -->
<g id="node3" class="node">
<title>github.com/mdlayher/cryptonl</title>
<g id="a_node3"><a xlink:href="https://github.com/mdlayher/cryptonl" xlink:title="github.com/mdlayher/cryptonl">
<ellipse fill="none" stroke="#000000" cx="501.1102" cy="-1313" rx="118.8789" ry="18"/>
<text text-anchor="middle" x="501.1102" y="-1309.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/mdlayher/cryptonl</text>
</a>
</g>
</g>
<!-- github.com/mdlayher/cryptonl&#45;&gt;github.com/mdlayher/netlink -->
<g id="edge2" class="edge">
<title>github.com/mdlayher/cryptonl&#45;&gt;github.com/mdlayher/netlink</title>
<path fill="none" stroke="#000000" d="M610.7334,-1305.9481C624.5338,-1300.8942 637.3585,-1293.5434 647.5479,-1283 763.2734,-1163.2529 785.5805,-604.2973 789.275,-471.404"/>
<polygon fill="#000000" stroke="#000000" points="792.7785,-471.3145 789.5441,-461.2255 785.7809,-471.1294 792.7785,-471.3145"/>
</g>
<!-- github.com/mdlayher/genetlink -->
<g id="node4" class="node">
<title>github.com/mdlayher/genetlink</title>
<g id="a_node4"><a xlink:href="https://github.com/mdlayher/genetlink" xlink:title="github.com/mdlayher/genetlink">
<ellipse fill="none" stroke="#000000" cx="501.1102" cy="-960" rx="122.3786" ry="18"/>
<text text-anchor="middle" x="501.1102" y="-956.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/mdlayher/genetlink</text>
</a>
</g>
</g>
<!-- github.com/mdlayher/genetlink&#45;&gt;github.com/mdlayher/netlink -->
<g id="edge3" class="edge">
<title>github.com/mdlayher/genetlink&#45;&gt;github.com/mdlayher/netlink</title>
<path fill="none" stroke="#000000" d="M512.2824,-941.9846C537.2353,-901.5876 599.1109,-800.521 647.5479,-714 696.8353,-625.9599 751.3273,-519.464 776.1997,-470.3016"/>
<polygon fill="#000000" stroke="#000000" points="779.3841,-471.76 780.7689,-461.256 773.136,-468.6038 779.3841,-471.76"/>
</g>
<!-- github.com/axatrax/l2tp -->
<g id="node5" class="node">
<title>github.com/axatrax/l2tp</title>
<g id="a_node5"><a xlink:href="https://github.com/axatrax/l2tp" xlink:title="github.com/axatrax/l2tp">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-1230" rx="95.5831" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-1226.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/axatrax/l2tp</text>
</a>
</g>
</g>
<!-- github.com/axatrax/l2tp&#45;&gt;github.com/mdlayher/genetlink -->
<g id="edge4" class="edge">
<title>github.com/axatrax/l2tp&#45;&gt;github.com/mdlayher/genetlink</title>
<path fill="none" stroke="#000000" d="M264.3393,-1225.7596C285.9946,-1221.6342 308.121,-1214.6346 326.6724,-1203 411.4328,-1149.8426 467.4112,-1039.0703 489.9239,-987.5067"/>
<polygon fill="#000000" stroke="#000000" points="493.2676,-988.589 493.9789,-978.018 486.8307,-985.8382 493.2676,-988.589"/>
</g>
<!-- github.com/digitalocean/go&#45;openvswitch -->
<g id="node6" class="node">
<title>github.com/digitalocean/go&#45;openvswitch</title>
<g id="a_node6"><a xlink:href="https://github.com/digitalocean/go-openvswitch" xlink:title="github.com/digitalocean/go&#45;openvswitch">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-1176" rx="155.1726" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-1172.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/digitalocean/go&#45;openvswitch</text>
</a>
</g>
</g>
<!-- github.com/digitalocean/go&#45;openvswitch&#45;&gt;github.com/mdlayher/genetlink -->
<g id="edge5" class="edge">
<title>github.com/digitalocean/go&#45;openvswitch&#45;&gt;github.com/mdlayher/genetlink</title>
<path fill="none" stroke="#000000" d="M288.675,-1164.1733C301.9335,-1160.3648 314.894,-1155.4158 326.6724,-1149 399.005,-1109.5999 457.6675,-1028.8489 484.8041,-986.7962"/>
<polygon fill="#000000" stroke="#000000" points="487.8588,-988.5148 490.2614,-978.196 481.9483,-984.7643 487.8588,-988.5148"/>
</g>
<!-- github.com/mdlayher/devlink -->
<g id="node7" class="node">
<title>github.com/mdlayher/devlink</title>
<g id="a_node7"><a xlink:href="https://github.com/mdlayher/devlink" xlink:title="github.com/mdlayher/devlink">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-1122" rx="116.1796" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-1118.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/mdlayher/devlink</text>
</a>
</g>
</g>
<!-- github.com/mdlayher/devlink&#45;&gt;github.com/mdlayher/genetlink -->
<g id="edge6" class="edge">
<title>github.com/mdlayher/devlink&#45;&gt;github.com/mdlayher/genetlink</title>
<path fill="none" stroke="#000000" d="M270.0065,-1112.2812C289.3033,-1108.3328 309.0157,-1102.787 326.6724,-1095 387.0749,-1068.361 445.2293,-1016.3812 476.7727,-985.2696"/>
<polygon fill="#000000" stroke="#000000" points="479.6082,-987.3837 484.204,-977.8376 474.6582,-982.4342 479.6082,-987.3837"/>
</g>
<!-- github.com/mdlayher/quota -->
<g id="node8" class="node">
<title>github.com/mdlayher/quota</title>
<g id="a_node8"><a xlink:href="https://github.com/mdlayher/quota" xlink:title="github.com/mdlayher/quota">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-1068" rx="109.381" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-1064.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/mdlayher/quota</text>
</a>
</g>
</g>
<!-- github.com/mdlayher/quota&#45;&gt;github.com/mdlayher/genetlink -->
<g id="edge7" class="edge">
<title>github.com/mdlayher/quota&#45;&gt;github.com/mdlayher/genetlink</title>
<path fill="none" stroke="#000000" d="M258.1644,-1057.0454C280.7514,-1053.0754 304.8604,-1047.8288 326.6724,-1041 374.644,-1025.9812 426.5199,-1000.6145 461.1179,-982.2644"/>
<polygon fill="#000000" stroke="#000000" points="462.802,-985.3329 469.9641,-977.5255 459.4965,-979.1625 462.802,-985.3329"/>
</g>
<!-- github.com/mdlayher/taskstats -->
<g id="node9" class="node">
<title>github.com/mdlayher/taskstats</title>
<g id="a_node9"><a xlink:href="https://github.com/mdlayher/taskstats" xlink:title="github.com/mdlayher/taskstats">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-1014" rx="119.6788" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-1010.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/mdlayher/taskstats</text>
</a>
</g>
</g>
<!-- github.com/mdlayher/taskstats&#45;&gt;github.com/mdlayher/genetlink -->
<g id="edge8" class="edge">
<title>github.com/mdlayher/taskstats&#45;&gt;github.com/mdlayher/genetlink</title>
<path fill="none" stroke="#000000" d="M252.4304,-1000.721C299.8893,-992.9496 359.9621,-983.1128 409.1751,-975.0542"/>
<polygon fill="#000000" stroke="#000000" points="409.8812,-978.4853 419.1842,-973.4153 408.75,-971.5773 409.8812,-978.4853"/>
</g>
<!-- github.com/mdlayher/wifi -->
<g id="node10" class="node">
<title>github.com/mdlayher/wifi</title>
<g id="a_node10"><a xlink:href="https://github.com/mdlayher/wifi" xlink:title="github.com/mdlayher/wifi">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-960" rx="103.9815" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-956.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/mdlayher/wifi</text>
</a>
</g>
</g>
<!-- github.com/mdlayher/wifi&#45;&gt;github.com/mdlayher/genetlink -->
<g id="edge9" class="edge">
<title>github.com/mdlayher/wifi&#45;&gt;github.com/mdlayher/genetlink</title>
<path fill="none" stroke="#000000" d="M275.6788,-960C305.0928,-960 337.4919,-960 368.3321,-960"/>
<polygon fill="#000000" stroke="#000000" points="368.7246,-963.5001 378.7246,-960 368.7245,-956.5001 368.7246,-963.5001"/>
</g>
<!-- github.com/Merovius/nbd -->
<g id="node11" class="node">
<title>github.com/Merovius/nbd</title>
<g id="a_node11"><a xlink:href="https://github.com/Merovius/nbd" xlink:title="github.com/Merovius/nbd">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-906" rx="103.1819" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-902.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/Merovius/nbd</text>
</a>
</g>
</g>
<!-- github.com/Merovius/nbd&#45;&gt;github.com/mdlayher/genetlink -->
<g id="edge10" class="edge">
<title>github.com/Merovius/nbd&#45;&gt;github.com/mdlayher/genetlink</title>
<path fill="none" stroke="#000000" d="M246.993,-918.3887C295.2157,-926.2851 358.0096,-936.5675 409.1103,-944.9352"/>
<polygon fill="#000000" stroke="#000000" points="408.7326,-948.4198 419.1668,-946.5819 409.8638,-941.5119 408.7326,-948.4198"/>
</g>
<!-- github.com/rtr7/router7 -->
<g id="node12" class="node">
<title>github.com/rtr7/router7</title>
<g id="a_node12"><a xlink:href="https://github.com/rtr7/router7" xlink:title="github.com/rtr7/router7">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-852" rx="94.4839" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-848.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/rtr7/router7</text>
</a>
</g>
</g>
<!-- github.com/rtr7/router7&#45;&gt;github.com/mdlayher/genetlink -->
<g id="edge11" class="edge">
<title>github.com/rtr7/router7&#45;&gt;github.com/mdlayher/genetlink</title>
<path fill="none" stroke="#000000" d="M250.9186,-861.7151C275.5276,-865.812 302.5094,-871.4351 326.6724,-879 374.644,-894.0188 426.5199,-919.3855 461.1179,-937.7356"/>
<polygon fill="#000000" stroke="#000000" points="459.4965,-940.8375 469.9641,-942.4745 462.802,-934.6671 459.4965,-940.8375"/>
</g>
<!-- github.com/u&#45;root/u&#45;bmc -->
<g id="node13" class="node">
<title>github.com/u&#45;root/u&#45;bmc</title>
<g id="a_node13"><a xlink:href="https://github.com/u-root/u-bmc" xlink:title="github.com/u&#45;root/u&#45;bmc">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-798" rx="100.9827" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-794.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/u&#45;root/u&#45;bmc</text>
</a>
</g>
</g>
<!-- github.com/u&#45;root/u&#45;bmc&#45;&gt;github.com/mdlayher/genetlink -->
<g id="edge12" class="edge">
<title>github.com/u&#45;root/u&#45;bmc&#45;&gt;github.com/mdlayher/genetlink</title>
<path fill="none" stroke="#000000" d="M261.4204,-806.0589C283.386,-810.065 306.386,-816.0532 326.6724,-825 387.0749,-851.639 445.2293,-903.6188 476.7727,-934.7304"/>
<polygon fill="#000000" stroke="#000000" points="474.6582,-937.5658 484.204,-942.1624 479.6082,-932.6163 474.6582,-937.5658"/>
</g>
<!-- golang.zx2c4.com/wireguard/wgctrl -->
<g id="node14" class="node">
<title>golang.zx2c4.com/wireguard/wgctrl</title>
<g id="a_node14"><a xlink:href="https://golang.zx2c4.com/wireguard/wgctrl" xlink:title="golang.zx2c4.com/wireguard/wgctrl">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-744" rx="139.1754" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-740.3" font-family="Times,serif" font-size="14.00" fill="#000000">golang.zx2c4.com/wireguard/wgctrl</text>
</a>
</g>
</g>
<!-- golang.zx2c4.com/wireguard/wgctrl&#45;&gt;github.com/mdlayher/genetlink -->
<g id="edge13" class="edge">
<title>golang.zx2c4.com/wireguard/wgctrl&#45;&gt;github.com/mdlayher/genetlink</title>
<path fill="none" stroke="#000000" d="M284.2004,-754.5868C299.0091,-758.5427 313.5719,-763.864 326.6724,-771 399.005,-810.4001 457.6675,-891.1511 484.8041,-933.2038"/>
<polygon fill="#000000" stroke="#000000" points="481.9483,-935.2357 490.2614,-941.804 487.8588,-931.4852 481.9483,-935.2357"/>
</g>
<!-- github.com/mdlayher/kobject -->
<g id="node15" class="node">
<title>github.com/mdlayher/kobject</title>
<g id="a_node15"><a xlink:href="https://github.com/mdlayher/kobject" xlink:title="github.com/mdlayher/kobject">
<ellipse fill="none" stroke="#000000" cx="501.1102" cy="-661" rx="115.8798" ry="18"/>
<text text-anchor="middle" x="501.1102" y="-657.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/mdlayher/kobject</text>
</a>
</g>
</g>
<!-- github.com/mdlayher/kobject&#45;&gt;github.com/mdlayher/netlink -->
<g id="edge14" class="edge">
<title>github.com/mdlayher/kobject&#45;&gt;github.com/mdlayher/netlink</title>
<path fill="none" stroke="#000000" d="M598.6533,-651.2474C615.7971,-646.7428 632.8379,-640.2701 647.5479,-631 711.0165,-591.0025 756.5745,-511.9527 777.347,-470.2422"/>
<polygon fill="#000000" stroke="#000000" points="780.5136,-471.7338 781.7468,-461.2109 774.2206,-468.668 780.5136,-471.7338"/>
</g>
<!-- github.com/florianl/go&#45;conntrack -->
<g id="node16" class="node">
<title>github.com/florianl/go&#45;conntrack</title>
<g id="a_node16"><a xlink:href="https://github.com/florianl/go-conntrack" xlink:title="github.com/florianl/go&#45;conntrack">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-524" rx="128.0773" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-520.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/florianl/go&#45;conntrack</text>
</a>
</g>
</g>
<!-- github.com/florianl/go&#45;conntrack&#45;&gt;github.com/mdlayher/netlink -->
<g id="edge15" class="edge">
<title>github.com/florianl/go&#45;conntrack&#45;&gt;github.com/mdlayher/netlink</title>
<path fill="none" stroke="#000000" d="M277.0466,-513.8001C373.7222,-503.9954 520.5725,-487.9044 647.5479,-469 667.216,-466.0718 688.3299,-462.4696 708.1165,-458.8899"/>
<polygon fill="#000000" stroke="#000000" points="708.8102,-462.3212 718.0183,-457.0808 707.5521,-455.4352 708.8102,-462.3212"/>
</g>
<!-- github.com/florianl/go&#45;nflog -->
<g id="node17" class="node">
<title>github.com/florianl/go&#45;nflog</title>
<g id="a_node17"><a xlink:href="https://github.com/florianl/go-nflog" xlink:title="github.com/florianl/go&#45;nflog">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-470" rx="112.3801" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-466.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/florianl/go&#45;nflog</text>
</a>
</g>
</g>
<!-- github.com/florianl/go&#45;nflog&#45;&gt;github.com/mdlayher/netlink -->
<g id="edge16" class="edge">
<title>github.com/florianl/go&#45;nflog&#45;&gt;github.com/mdlayher/netlink</title>
<path fill="none" stroke="#000000" d="M280.1508,-465.2506C389.1846,-460.4916 556.624,-453.1834 669.5731,-448.2535"/>
<polygon fill="#000000" stroke="#000000" points="669.81,-451.7466 679.6479,-447.8138 669.5047,-444.7533 669.81,-451.7466"/>
</g>
<!-- github.com/florianl/go&#45;nfqueue -->
<g id="node18" class="node">
<title>github.com/florianl/go&#45;nfqueue</title>
<g id="a_node18"><a xlink:href="https://github.com/florianl/go-nfqueue" xlink:title="github.com/florianl/go&#45;nfqueue">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-416" rx="122.3786" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-412.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/florianl/go&#45;nfqueue</text>
</a>
</g>
</g>
<!-- github.com/florianl/go&#45;nfqueue&#45;&gt;github.com/mdlayher/netlink -->
<g id="edge17" class="edge">
<title>github.com/florianl/go&#45;nfqueue&#45;&gt;github.com/mdlayher/netlink</title>
<path fill="none" stroke="#000000" d="M288.7819,-421.1261C397.8587,-425.887 559.5469,-432.9442 669.5556,-437.7457"/>
<polygon fill="#000000" stroke="#000000" points="669.5611,-441.2492 679.7043,-438.1887 669.8664,-434.2558 669.5611,-441.2492"/>
</g>
<!-- github.com/google/nftables -->
<g id="node19" class="node">
<title>github.com/google/nftables</title>
<g id="a_node19"><a xlink:href="https://github.com/google/nftables" xlink:title="github.com/google/nftables">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-362" rx="107.781" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-358.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/google/nftables</text>
</a>
</g>
</g>
<!-- github.com/google/nftables&#45;&gt;github.com/mdlayher/netlink -->
<g id="edge18" class="edge">
<title>github.com/google/nftables&#45;&gt;github.com/mdlayher/netlink</title>
<path fill="none" stroke="#000000" d="M261.4388,-371.9156C357.3042,-382.7128 513.3379,-400.995 647.5479,-420 664.9576,-422.4653 683.5294,-425.3087 701.3161,-428.1371"/>
<polygon fill="#000000" stroke="#000000" points="701.2554,-431.6719 711.6832,-429.7978 702.3627,-424.7601 701.2554,-431.6719"/>
</g>
<!-- github.com/ti&#45;mo/netfilter -->
<g id="node20" class="node">
<title>github.com/ti&#45;mo/netfilter</title>
<g id="a_node20"><a xlink:href="https://github.com/ti-mo/netfilter" xlink:title="github.com/ti&#45;mo/netfilter">
<ellipse fill="none" stroke="#000000" cx="501.1102" cy="-572" rx="103.1819" ry="18"/>
<text text-anchor="middle" x="501.1102" y="-568.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/ti&#45;mo/netfilter</text>
</a>
</g>
</g>
<!-- github.com/ti&#45;mo/netfilter&#45;&gt;github.com/mdlayher/netlink -->
<g id="edge19" class="edge">
<title>github.com/ti&#45;mo/netfilter&#45;&gt;github.com/mdlayher/netlink</title>
<path fill="none" stroke="#000000" d="M564.7651,-557.7322C590.9674,-550.8436 621.2746,-541.5409 647.5479,-530 687.2088,-512.5784 729.1179,-485.8262 757.1173,-466.5875"/>
<polygon fill="#000000" stroke="#000000" points="759.1243,-469.455 765.3424,-460.8767 755.132,-463.7051 759.1243,-469.455"/>
</g>
<!-- github.com/ti&#45;mo/conntrack -->
<g id="node21" class="node">
<title>github.com/ti&#45;mo/conntrack</title>
<g id="a_node21"><a xlink:href="https://github.com/ti-mo/conntrack" xlink:title="github.com/ti&#45;mo/conntrack">
<ellipse fill="none" stroke="#000000" cx="171.3362" cy="-578" rx="110.4804" ry="18"/>
<text text-anchor="middle" x="171.3362" y="-574.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/ti&#45;mo/conntrack</text>
</a>
</g>
</g>
<!-- github.com/ti&#45;mo/conntrack&#45;&gt;github.com/ti&#45;mo/netfilter -->
<g id="edge20" class="edge">
<title>github.com/ti&#45;mo/conntrack&#45;&gt;github.com/ti&#45;mo/netfilter</title>
<path fill="none" stroke="#000000" d="M281.1462,-576.0021C315.5084,-575.3769 353.4762,-574.6861 388.0577,-574.0569"/>
<polygon fill="#000000" stroke="#000000" points="388.2582,-577.5539 398.1929,-573.8725 388.1308,-570.5551 388.2582,-577.5539"/>
</g>
<!-- github.com/ema/qdisc -->
<g id="node22" class="node">
<title>github.com/ema/qdisc</title>
<g id="a_node22"><a xlink:href="https://github.com/ema/qdisc" xlink:title="github.com/ema/qdisc">
<ellipse fill="none" stroke="#000000" cx="501.1102" cy="-279" rx="89.8845" ry="18"/>
<text text-anchor="middle" x="501.1102" y="-275.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/ema/qdisc</text>
</a>
</g>
</g>
<!-- github.com/ema/qdisc&#45;&gt;github.com/mdlayher/netlink -->
<g id="edge21" class="edge">
<title>github.com/ema/qdisc&#45;&gt;github.com/mdlayher/netlink</title>
<path fill="none" stroke="#000000" d="M553.6635,-293.5936C582.3585,-302.6386 617.9653,-315.6578 647.5479,-332 691.4973,-356.2788 736.197,-393.6346 763.5001,-418.1958"/>
<polygon fill="#000000" stroke="#000000" points="761.3065,-420.9318 771.0595,-425.0704 766.0161,-415.753 761.3065,-420.9318"/>
</g>
<!-- github.com/florianl/go&#45;tc -->
<g id="node23" class="node">
<title>github.com/florianl/go&#45;tc</title>
<g id="a_node23"><a xlink:href="https://github.com/florianl/go-tc" xlink:title="github.com/florianl/go&#45;tc">
<ellipse fill="none" stroke="#000000" cx="501.1102" cy="-225" rx="100.1823" ry="18"/>
<text text-anchor="middle" x="501.1102" y="-221.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/florianl/go&#45;tc</text>
</a>
</g>
</g>
<!-- github.com/florianl/go&#45;tc&#45;&gt;github.com/mdlayher/netlink -->
<g id="edge22" class="edge">
<title>github.com/florianl/go&#45;tc&#45;&gt;github.com/mdlayher/netlink</title>
<path fill="none" stroke="#000000" d="M594.8153,-231.5626C613.2418,-235.7365 631.7408,-242.172 647.5479,-252 712.2318,-292.2171 757.5371,-373.4108 777.8719,-415.8163"/>
<polygon fill="#000000" stroke="#000000" points="774.7542,-417.4118 782.1666,-424.982 781.0929,-414.4417 774.7542,-417.4118"/>
</g>
<!-- github.com/jsimonetti/rtnetlink -->
<g id="node24" class="node">
<title>github.com/jsimonetti/rtnetlink</title>
<g id="a_node24"><a xlink:href="https://github.com/jsimonetti/rtnetlink" xlink:title="github.com/jsimonetti/rtnetlink">
<ellipse fill="none" stroke="#000000" cx="501.1102" cy="-171" rx="121.5784" ry="18"/>
<text text-anchor="middle" x="501.1102" y="-167.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/jsimonetti/rtnetlink</text>
</a>
</g>
</g>
<!-- github.com/jsimonetti/rtnetlink&#45;&gt;github.com/mdlayher/netlink -->
<g id="edge23" class="edge">
<title>github.com/jsimonetti/rtnetlink&#45;&gt;github.com/mdlayher/netlink</title>
<path fill="none" stroke="#000000" d="M608.2934,-179.5458C622.2871,-183.7949 635.8152,-189.7416 647.5479,-198 724.8917,-252.4412 766.3728,-363.2908 782.2353,-415.1194"/>
<polygon fill="#000000" stroke="#000000" points="778.9529,-416.3615 785.1523,-424.9532 785.6639,-414.3707 778.9529,-416.3615"/>
</g>
<!-- gitlab.com/mergetb/tech/rtnl -->
<g id="node25" class="node">
<title>gitlab.com/mergetb/tech/rtnl</title>
<g id="a_node25"><a xlink:href="https://gitlab.com/mergetb/tech/rtnl" xlink:title="gitlab.com/mergetb/tech/rtnl">
<ellipse fill="none" stroke="#000000" cx="501.1102" cy="-117" rx="112.3801" ry="18"/>
<text text-anchor="middle" x="501.1102" y="-113.3" font-family="Times,serif" font-size="14.00" fill="#000000">gitlab.com/mergetb/tech/rtnl</text>
</a>
</g>
</g>
<!-- gitlab.com/mergetb/tech/rtnl&#45;&gt;github.com/mdlayher/netlink -->
<g id="edge24" class="edge">
<title>gitlab.com/mergetb/tech/rtnl&#45;&gt;github.com/mdlayher/netlink</title>
<path fill="none" stroke="#000000" d="M605.9213,-123.7549C620.9013,-128.1694 635.3432,-134.6381 647.5479,-144 738.1381,-213.4898 773.8638,-355.0819 785.3329,-415.1061"/>
<polygon fill="#000000" stroke="#000000" points="781.9009,-415.7955 787.1431,-425.0025 788.7866,-414.536 781.9009,-415.7955"/>
</g>
<!-- github.com/SpComb/go&#45;onewire -->
<g id="node26" class="node">
<title>github.com/SpComb/go&#45;onewire</title>
<g id="a_node26"><a xlink:href="https://github.com/SpComb/go-onewire" xlink:title="github.com/SpComb/go&#45;onewire">
<ellipse fill="none" stroke="#000000" cx="501.1102" cy="-34" rx="127.2775" ry="18"/>
<text text-anchor="middle" x="501.1102" y="-30.3" font-family="Times,serif" font-size="14.00" fill="#000000">github.com/SpComb/go&#45;onewire</text>
</a>
</g>
</g>
<!-- github.com/SpComb/go&#45;onewire&#45;&gt;github.com/mdlayher/netlink -->
<g id="edge25" class="edge">
<title>github.com/SpComb/go&#45;onewire&#45;&gt;github.com/mdlayher/netlink</title>
<path fill="none" stroke="#000000" d="M577.4569,-48.4733C602.3155,-56.3703 628.4063,-68.484 647.5479,-87 744.3092,-180.5992 777.0533,-348.493 786.5385,-414.8793"/>
<polygon fill="#000000" stroke="#000000" points="783.0981,-415.5551 787.9134,-424.9924 790.0343,-414.612 783.0981,-415.5551"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 27 KiB

View file

@ -3,25 +3,91 @@
package netlink package netlink
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
// getThreadNetNS gets the network namespace file descriptor of the thread the current goroutine // errNetNSDisabled is returned when network namespaces are unavailable on
// is running on. Make sure to call runtime.LockOSThread() before this so the goroutine does not // a given system.
// get scheduled on another thread in the meantime. var errNetNSDisabled = errors.New("netlink: network namespaces are not enabled on this system")
func getThreadNetNS() (int, error) {
file, err := os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/net", unix.Getpid(), unix.Gettid())) // A netNS is a handle that can manipulate network namespaces.
if err != nil { //
return -1, err // Operations performed on a netNS must use runtime.LockOSThread before
} // manipulating any network namespaces.
return int(file.Fd()), nil type netNS struct {
// The handle to a network namespace.
f *os.File
// Indicates if network namespaces are disabled on this system, and thus
// operations should become a no-op or return errors.
disabled bool
} }
// setThreadNetNS sets the network namespace of the thread of the current goroutine to // threadNetNS constructs a netNS using the network namespace of the calling
// the namespace described by the user-provided file descriptor. // thread. If the namespace is not the default namespace, runtime.LockOSThread
func setThreadNetNS(fd int) error { // should be invoked first.
return unix.Setns(fd, unix.CLONE_NEWNET) func threadNetNS() (*netNS, error) {
return fileNetNS(fmt.Sprintf("/proc/self/task/%d/ns/net", unix.Gettid()))
}
// fileNetNS opens file and creates a netNS. fileNetNS should only be called
// directly in tests.
func fileNetNS(file string) (*netNS, error) {
f, err := os.Open(file)
switch {
case err == nil:
return &netNS{f: f}, nil
case os.IsNotExist(err):
// Network namespaces are not enabled on this system. Use this signal
// to return errors elsewhere if the caller explicitly asks for a
// network namespace to be set.
return &netNS{disabled: true}, nil
default:
return nil, err
}
}
// Close releases the handle to a network namespace.
func (n *netNS) Close() error {
return n.do(func() error {
return n.f.Close()
})
}
// FD returns a file descriptor which represents the network namespace.
func (n *netNS) FD() int {
if n.disabled {
// No reasonable file descriptor value in this case, so specify a
// non-existent one.
return -1
}
return int(n.f.Fd())
}
// Restore restores the original network namespace for the calling thread.
func (n *netNS) Restore() error {
return n.do(func() error {
return n.Set(n.FD())
})
}
// Set sets a new network namespace for the current thread using fd.
func (n *netNS) Set(fd int) error {
return n.do(func() error {
return os.NewSyscallError("setns", unix.Setns(fd, unix.CLONE_NEWNET))
})
}
// do runs fn if network namespaces are enabled on this system.
func (n *netNS) do(fn func() error) error {
if n.disabled {
return errNetNSDisabled
}
return fn()
} }

View file

@ -1,8 +1,6 @@
package nlenc package nlenc
import ( import "encoding/binary"
"encoding/binary"
)
// NativeEndian returns the native byte order of this system. // NativeEndian returns the native byte order of this system.
func NativeEndian() binary.ByteOrder { func NativeEndian() binary.ByteOrder {

View file

@ -10,5 +10,9 @@ func Bytes(s string) []byte {
// String returns a string with the contents of b from a null-terminated // String returns a string with the contents of b from a null-terminated
// byte slice. // byte slice.
func String(b []byte) string { func String(b []byte) string {
return string(bytes.TrimSuffix(b, []byte{0x00})) // If the string has more than one NULL terminator byte, we want to remove
// all of them before returning the string to the caller; hence the use of
// strings.TrimRight instead of strings.TrimSuffix (which previously only
// removed a single NULL).
return string(bytes.TrimRight(b, "\x00"))
} }

View file

@ -0,0 +1,12 @@
//+build go1.12
package netlink
import (
"os"
"syscall"
)
func newRawConn(fd *os.File) (syscall.RawConn, error) {
return fd.SyscallConn()
}

32
vendor/github.com/mdlayher/netlink/rawconn_lt_1.12.go generated vendored Normal file
View file

@ -0,0 +1,32 @@
//+build !go1.12
package netlink
import (
"os"
"syscall"
)
func newRawConn(fd *os.File) (syscall.RawConn, error) {
return &rawConn{fd: fd.Fd()}, nil
}
var _ syscall.RawConn = &rawConn{}
// A rawConn is a syscall.RawConn.
type rawConn struct {
fd uintptr
}
func (rc *rawConn) Control(f func(fd uintptr)) error {
f(rc.fd)
return nil
}
func (rc *rawConn) Read(_ func(fd uintptr) (done bool)) error {
return notSupported("syscall-conn-read")
}
func (rc *rawConn) Write(_ func(fd uintptr) (done bool)) error {
return notSupported("syscall-conn-write")
}

View file

@ -1,27 +0,0 @@
// +build linux,!386
package netlink
import (
"unsafe"
"golang.org/x/sys/unix"
)
// setsockopt provides access to the setsockopt syscall.
func setsockopt(fd, level, name int, v unsafe.Pointer, l uint32) error {
_, _, errno := unix.Syscall6(
unix.SYS_SETSOCKOPT,
uintptr(fd),
uintptr(level),
uintptr(name),
uintptr(v),
uintptr(l),
0,
)
if errno != 0 {
return error(errno)
}
return nil
}

View file

@ -1,36 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux,386
package netlink
import (
"syscall"
"unsafe"
)
const (
sysSETSOCKOPT = 0xe
)
func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
// setsockopt provides access to the setsockopt syscall.
func setsockopt(fd, level, name int, v unsafe.Pointer, l uint32) error {
_, errno := socketcall(
sysSETSOCKOPT,
uintptr(fd),
uintptr(level),
uintptr(name),
uintptr(v),
uintptr(l),
0,
)
if errno != 0 {
return error(errno)
}
return nil
}

View file

@ -1,6 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
TEXT ·socketcall(SB),4,$0-36
JMP syscall·socketcall(SB)

View file

@ -5,7 +5,7 @@ os:
- linux - linux
sudo: required sudo: required
before_install: before_install:
- go get github.com/golang/lint/golint - go get golang.org/x/lint/golint
- go get honnef.co/go/tools/cmd/staticcheck - go get honnef.co/go/tools/cmd/staticcheck
- go get -d -t ./... - go get -d -t ./...
script: script:

View file

@ -76,7 +76,7 @@ func (c *client) Interfaces() ([]*Interface, error) {
}, },
} }
flags := netlink.HeaderFlagsRequest | netlink.HeaderFlagsDump flags := netlink.Request | netlink.Dump
msgs, err := c.c.Execute(req, c.familyID, flags) msgs, err := c.c.Execute(req, c.familyID, flags)
if err != nil { if err != nil {
return nil, err return nil, err
@ -106,7 +106,7 @@ func (c *client) BSS(ifi *Interface) (*BSS, error) {
Data: b, Data: b,
} }
flags := netlink.HeaderFlagsRequest | netlink.HeaderFlagsDump flags := netlink.Request | netlink.Dump
msgs, err := c.c.Execute(req, c.familyID, flags) msgs, err := c.c.Execute(req, c.familyID, flags)
if err != nil { if err != nil {
return nil, err return nil, err
@ -140,7 +140,7 @@ func (c *client) StationInfo(ifi *Interface) ([]*StationInfo, error) {
Data: b, Data: b,
} }
flags := netlink.HeaderFlagsRequest | netlink.HeaderFlagsDump flags := netlink.Request | netlink.Dump
msgs, err := c.c.Execute(req, c.familyID, flags) msgs, err := c.c.Execute(req, c.familyID, flags)
if err != nil { if err != nil {
return nil, err return nil, err
@ -164,7 +164,6 @@ func (c *client) StationInfo(ifi *Interface) ([]*StationInfo, error) {
return stations, nil return stations, nil
} }
// checkMessages verifies that response messages from generic netlink contain // checkMessages verifies that response messages from generic netlink contain
// the command and family version we expect. // the command and family version we expect.
func (c *client) checkMessages(msgs []genetlink.Message, command uint8) error { func (c *client) checkMessages(msgs []genetlink.Message, command uint8) error {

View file

@ -1,6 +1,8 @@
// WARNING: This file has automatically been generated on Thu, 29 Dec 2016 08:53:57 EST. // WARNING: This file has automatically been generated on Thu, 29 Dec 2016 08:53:57 EST.
// By https://git.io/cgogen. DO NOT EDIT. // By https://git.io/cgogen. DO NOT EDIT.
//lint:file-ignore U1000 Ignore all unused code, it's generated.
package nl80211 package nl80211
const ( const (

View file

@ -129,7 +129,8 @@ func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) { func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) {
offset := int(ins.Off) offset := int(ins.Off)
if !inBounds(len(in), offset, 0) { // Size of LoadMemShift is always 1 byte
if !inBounds(len(in), offset, 1) {
return 0, false return 0, false
} }

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le s390x // +build arm64 amd64 ppc64 ppc64le mips64 mips64le riscv64 s390x
// +build linux // +build linux
package socket package socket

View file

@ -16,14 +16,6 @@ package socket
*/ */
import "C" import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec type iovec C.struct_iovec
type msghdr C.struct_msghdr type msghdr C.struct_msghdr

View file

@ -16,14 +16,6 @@ package socket
*/ */
import "C" import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec type iovec C.struct_iovec
type msghdr C.struct_msghdr type msghdr C.struct_msghdr

View file

@ -16,14 +16,6 @@ package socket
*/ */
import "C" import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec type iovec C.struct_iovec
type msghdr C.struct_msghdr type msghdr C.struct_msghdr

View file

@ -16,14 +16,6 @@ package socket
*/ */
import "C" import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec type iovec C.struct_iovec
type msghdr C.struct_msghdr type msghdr C.struct_msghdr

View file

@ -18,14 +18,6 @@ package socket
*/ */
import "C" import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec type iovec C.struct_iovec
type msghdr C.struct_msghdr type msghdr C.struct_msghdr

View file

@ -16,14 +16,6 @@ package socket
*/ */
import "C" import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec type iovec C.struct_iovec
type msghdr C.struct_msghdr type msghdr C.struct_msghdr

View file

@ -16,14 +16,6 @@ package socket
*/ */
import "C" import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec type iovec C.struct_iovec
type msghdr C.struct_msghdr type msghdr C.struct_msghdr

View file

@ -16,14 +16,6 @@ package socket
*/ */
import "C" import "C"
const (
sysAF_UNSPEC = C.AF_UNSPEC
sysAF_INET = C.AF_INET
sysAF_INET6 = C.AF_INET6
sysSOCK_RAW = C.SOCK_RAW
)
type iovec C.struct_iovec type iovec C.struct_iovec
type msghdr C.struct_msghdr type msghdr C.struct_msghdr

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le s390x // +build arm64 amd64 ppc64 ppc64le mips64 mips64le riscv64 s390x
// +build aix darwin dragonfly freebsd linux netbsd openbsd // +build aix darwin dragonfly freebsd linux netbsd openbsd
package socket package socket

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le s390x // +build arm64 amd64 ppc64 ppc64le mips64 mips64le riscv64 s390x
// +build linux // +build linux
package socket package socket

View file

@ -0,0 +1,17 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package socket
import "golang.org/x/sys/unix"
const (
sysAF_UNSPEC = unix.AF_UNSPEC
sysAF_INET = unix.AF_INET
sysAF_INET6 = unix.AF_INET6
sysSOCK_RAW = unix.SOCK_RAW
)

View file

@ -0,0 +1,12 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build riscv64
package socket
const (
sysRECVMMSG = 0xf3
sysSENDMMSG = 0x10d
)

View file

@ -33,7 +33,7 @@ func marshalSockaddr(ip net.IP, port int, zone string) []byte {
if ip4 := ip.To4(); ip4 != nil { if ip4 := ip.To4(); ip4 != nil {
b := make([]byte, sizeofSockaddrInet) b := make([]byte, sizeofSockaddrInet)
switch runtime.GOOS { switch runtime.GOOS {
case "android", "linux", "solaris", "windows": case "android", "illumos", "linux", "solaris", "windows":
NativeEndian.PutUint16(b[:2], uint16(sysAF_INET)) NativeEndian.PutUint16(b[:2], uint16(sysAF_INET))
default: default:
b[0] = sizeofSockaddrInet b[0] = sizeofSockaddrInet
@ -46,7 +46,7 @@ func marshalSockaddr(ip net.IP, port int, zone string) []byte {
if ip6 := ip.To16(); ip6 != nil && ip.To4() == nil { if ip6 := ip.To16(); ip6 != nil && ip.To4() == nil {
b := make([]byte, sizeofSockaddrInet6) b := make([]byte, sizeofSockaddrInet6)
switch runtime.GOOS { switch runtime.GOOS {
case "android", "linux", "solaris", "windows": case "android", "illumos", "linux", "solaris", "windows":
NativeEndian.PutUint16(b[:2], uint16(sysAF_INET6)) NativeEndian.PutUint16(b[:2], uint16(sysAF_INET6))
default: default:
b[0] = sizeofSockaddrInet6 b[0] = sizeofSockaddrInet6
@ -68,7 +68,7 @@ func parseInetAddr(b []byte, network string) (net.Addr, error) {
} }
var af int var af int
switch runtime.GOOS { switch runtime.GOOS {
case "android", "linux", "solaris", "windows": case "android", "illumos", "linux", "solaris", "windows":
af = int(NativeEndian.Uint16(b[:2])) af = int(NativeEndian.Uint16(b[:2]))
default: default:
af = int(b[1]) af = int(b[1])

View file

@ -7,6 +7,8 @@ package socket
import ( import (
"syscall" "syscall"
"unsafe" "unsafe"
"golang.org/x/sys/windows"
) )
func probeProtocolStack() int { func probeProtocolStack() int {
@ -15,11 +17,11 @@ func probeProtocolStack() int {
} }
const ( const (
sysAF_UNSPEC = 0x0 sysAF_UNSPEC = windows.AF_UNSPEC
sysAF_INET = 0x2 sysAF_INET = windows.AF_INET
sysAF_INET6 = 0x17 sysAF_INET6 = windows.AF_INET6
sysSOCK_RAW = 0x3 sysSOCK_RAW = windows.SOCK_RAW
) )
type sockaddrInet struct { type sockaddrInet struct {

View file

@ -6,14 +6,6 @@
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x18
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint64 Len uint64

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_darwin.go // cgo -godefs defs_darwin.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x1e
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint32 Len uint32

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_darwin.go // cgo -godefs defs_darwin.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x1e
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint64 Len uint64

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_darwin.go // cgo -godefs defs_darwin.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x1e
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint32 Len uint32

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_darwin.go // cgo -godefs defs_darwin.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x1e
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint64 Len uint64

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_dragonfly.go // cgo -godefs defs_dragonfly.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x1c
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint64 Len uint64

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go // cgo -godefs defs_freebsd.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x1c
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint32 Len uint32

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go // cgo -godefs defs_freebsd.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x1c
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint64 Len uint64

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go // cgo -godefs defs_freebsd.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x1c
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint32 Len uint32

View file

@ -0,0 +1,53 @@
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen int32
Pad_cgo_1 [4]byte
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
type sockaddrInet struct {
Len uint8
Family uint8
Port uint16
Addr [4]byte /* in_addr */
Zero [8]int8
}
type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
sizeofCmsghdr = 0xc
sizeofSockaddrInet = 0x10
sizeofSockaddrInet6 = 0x1c
)

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go // cgo -godefs defs_linux.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0xa
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint32 Len uint32

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go // cgo -godefs defs_linux.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0xa
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint64 Len uint64

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go // cgo -godefs defs_linux.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0xa
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint32 Len uint32

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go // cgo -godefs defs_linux.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0xa
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint64 Len uint64

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go // cgo -godefs defs_linux.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0xa
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint32 Len uint32

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go // cgo -godefs defs_linux.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0xa
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint64 Len uint64

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go // cgo -godefs defs_linux.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0xa
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint64 Len uint64

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go // cgo -godefs defs_linux.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0xa
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint32 Len uint32

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go // cgo -godefs defs_linux.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0xa
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint64 Len uint64

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go // cgo -godefs defs_linux.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0xa
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint64 Len uint64

View file

@ -0,0 +1,59 @@
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
// +build riscv64
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint64
Control *byte
Controllen uint64
Flags int32
Pad_cgo_0 [4]byte
}
type mmsghdr struct {
Hdr msghdr
Len uint32
Pad_cgo_0 [4]byte
}
type cmsghdr struct {
Len uint64
Level int32
Type int32
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x38
sizeofMmsghdr = 0x40
sizeofCmsghdr = 0x10
sizeofSockaddrInet = 0x10
sizeofSockaddrInet6 = 0x1c
)

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go // cgo -godefs defs_linux.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0xa
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint64 Len uint64

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_netbsd.go // cgo -godefs defs_netbsd.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x18
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint32 Len uint32

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_netbsd.go // cgo -godefs defs_netbsd.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x18
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint64 Len uint64

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_netbsd.go // cgo -godefs defs_netbsd.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x18
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint32 Len uint32

View file

@ -0,0 +1,60 @@
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_netbsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen int32
Pad_cgo_1 [4]byte
Control *byte
Controllen uint32
Flags int32
}
type mmsghdr struct {
Hdr msghdr
Len uint32
Pad_cgo_0 [4]byte
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
type sockaddrInet struct {
Len uint8
Family uint8
Port uint16
Addr [4]byte /* in_addr */
Zero [8]int8
}
type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
sizeofMmsghdr = 0x40
sizeofCmsghdr = 0xc
sizeofSockaddrInet = 0x10
sizeofSockaddrInet6 = 0x1c
)

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go // cgo -godefs defs_openbsd.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x18
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint32 Len uint32

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go // cgo -godefs defs_openbsd.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x18
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint64 Len uint64

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go // cgo -godefs defs_openbsd.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x18
sysSOCK_RAW = 0x3
)
type iovec struct { type iovec struct {
Base *byte Base *byte
Len uint32 Len uint32

View file

@ -0,0 +1,53 @@
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen uint32
Pad_cgo_1 [4]byte
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
type sockaddrInet struct {
Len uint8
Family uint8
Port uint16
Addr [4]byte /* in_addr */
Zero [8]int8
}
type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
sizeofCmsghdr = 0xc
sizeofSockaddrInet = 0x10
sizeofSockaddrInet6 = 0x1c
)

View file

@ -1,16 +1,8 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_solaris.go // cgo -godefs defs_solaris.go
package socket package socket
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0x1a
sysSOCK_RAW = 0x4
)
type iovec struct { type iovec struct {
Base *int8 Base *int8
Len uint64 Len uint64

View file

@ -1,4 +1,4 @@
// Created by cgo -godefs - DO NOT EDIT // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_darwin.go // cgo -godefs defs_darwin.go
package ipv4 package ipv4

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