Update netlink dependency.
This commit is contained in:
parent
699380d687
commit
0de29de33e
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
@ -176,11 +176,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/vishvananda/netlink",
|
"ImportPath": "github.com/vishvananda/netlink",
|
||||||
"Rev": "fe3b5664d23a11b52ba59bece4ff29c52772a56b"
|
"Rev": "b71e0bb214aebd980216cb2516e8bd7bca9e9672"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/vishvananda/netlink/nl",
|
"ImportPath": "github.com/vishvananda/netlink/nl",
|
||||||
"Rev": "fe3b5664d23a11b52ba59bece4ff29c52772a56b"
|
"Rev": "b71e0bb214aebd980216cb2516e8bd7bca9e9672"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/vishvananda/netns",
|
"ImportPath": "github.com/vishvananda/netns",
|
||||||
|
5
vendor/github.com/vishvananda/netlink/.travis.yml
generated
vendored
5
vendor/github.com/vishvananda/netlink/.travis.yml
generated
vendored
@ -4,5 +4,10 @@ before_script:
|
|||||||
- sudo sed -i -e 's/^Defaults\tsecure_path.*$//' /etc/sudoers
|
- sudo sed -i -e 's/^Defaults\tsecure_path.*$//' /etc/sudoers
|
||||||
# modprobe ip_gre or else the first gre device can't be deleted
|
# modprobe ip_gre or else the first gre device can't be deleted
|
||||||
- sudo modprobe ip_gre
|
- sudo modprobe ip_gre
|
||||||
|
# modprobe nf_conntrack for the conntrack testing
|
||||||
|
- sudo modprobe nf_conntrack
|
||||||
|
- sudo modprobe nf_conntrack_netlink
|
||||||
|
- sudo modprobe nf_conntrack_ipv4
|
||||||
|
- sudo modprobe nf_conntrack_ipv6
|
||||||
install:
|
install:
|
||||||
- go get github.com/vishvananda/netns
|
- go get github.com/vishvananda/netns
|
||||||
|
12
vendor/github.com/vishvananda/netlink/addr.go
generated
vendored
12
vendor/github.com/vishvananda/netlink/addr.go
generated
vendored
@ -10,11 +10,13 @@ import (
|
|||||||
// include a mask, so it stores the address as a net.IPNet.
|
// include a mask, so it stores the address as a net.IPNet.
|
||||||
type Addr struct {
|
type Addr struct {
|
||||||
*net.IPNet
|
*net.IPNet
|
||||||
Label string
|
Label string
|
||||||
Flags int
|
Flags int
|
||||||
Scope int
|
Scope int
|
||||||
Peer *net.IPNet
|
Peer *net.IPNet
|
||||||
Broadcast net.IP
|
Broadcast net.IP
|
||||||
|
PreferedLft int
|
||||||
|
ValidLft int
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns $ip/$netmask $label
|
// String returns $ip/$netmask $label
|
||||||
|
29
vendor/github.com/vishvananda/netlink/addr_linux.go
generated
vendored
29
vendor/github.com/vishvananda/netlink/addr_linux.go
generated
vendored
@ -27,6 +27,19 @@ func (h *Handle) AddrAdd(link Link, addr *Addr) error {
|
|||||||
return h.addrHandle(link, addr, req)
|
return h.addrHandle(link, addr, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddrReplace will replace (or, if not present, add) an IP address on a link device.
|
||||||
|
// Equivalent to: `ip addr replace $addr dev $link`
|
||||||
|
func AddrReplace(link Link, addr *Addr) error {
|
||||||
|
return pkgHandle.AddrReplace(link, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddrReplace will replace (or, if not present, add) an IP address on a link device.
|
||||||
|
// Equivalent to: `ip addr replace $addr dev $link`
|
||||||
|
func (h *Handle) AddrReplace(link Link, addr *Addr) error {
|
||||||
|
req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE|syscall.NLM_F_ACK)
|
||||||
|
return h.addrHandle(link, addr, req)
|
||||||
|
}
|
||||||
|
|
||||||
// AddrDel will delete an IP address from a link device.
|
// AddrDel will delete an IP address from a link device.
|
||||||
// Equivalent to: `ip addr del $addr dev $link`
|
// Equivalent to: `ip addr del $addr dev $link`
|
||||||
func AddrDel(link Link, addr *Addr) error {
|
func AddrDel(link Link, addr *Addr) error {
|
||||||
@ -186,6 +199,10 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
|
|||||||
addr.Label = string(attr.Value[:len(attr.Value)-1])
|
addr.Label = string(attr.Value[:len(attr.Value)-1])
|
||||||
case IFA_FLAGS:
|
case IFA_FLAGS:
|
||||||
addr.Flags = int(native.Uint32(attr.Value[0:4]))
|
addr.Flags = int(native.Uint32(attr.Value[0:4]))
|
||||||
|
case nl.IFA_CACHEINFO:
|
||||||
|
ci := nl.DeserializeIfaCacheInfo(attr.Value)
|
||||||
|
addr.PreferedLft = int(ci.IfaPrefered)
|
||||||
|
addr.ValidLft = int(ci.IfaValid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,6 +220,10 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
|
|||||||
type AddrUpdate struct {
|
type AddrUpdate struct {
|
||||||
LinkAddress net.IPNet
|
LinkAddress net.IPNet
|
||||||
LinkIndex int
|
LinkIndex int
|
||||||
|
Flags int
|
||||||
|
Scope int
|
||||||
|
PreferedLft int
|
||||||
|
ValidLft int
|
||||||
NewAddr bool // true=added false=deleted
|
NewAddr bool // true=added false=deleted
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,7 +271,13 @@ func addrSubscribe(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-cha
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
ch <- AddrUpdate{LinkAddress: *addr.IPNet, LinkIndex: ifindex, NewAddr: msgType == syscall.RTM_NEWADDR}
|
ch <- AddrUpdate{LinkAddress: *addr.IPNet,
|
||||||
|
LinkIndex: ifindex,
|
||||||
|
NewAddr: msgType == syscall.RTM_NEWADDR,
|
||||||
|
Flags: addr.Flags,
|
||||||
|
Scope: addr.Scope,
|
||||||
|
PreferedLft: addr.PreferedLft,
|
||||||
|
ValidLft: addr.ValidLft}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
193
vendor/github.com/vishvananda/netlink/addr_test.go
generated
vendored
Normal file
193
vendor/github.com/vishvananda/netlink/addr_test.go
generated
vendored
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddrAdd(t *testing.T) {
|
||||||
|
DoTestAddr(t, AddrAdd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddrReplace(t *testing.T) {
|
||||||
|
DoTestAddr(t, AddrReplace)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DoTestAddr(t *testing.T, FunctionUndertest func(Link, *Addr) error) {
|
||||||
|
if os.Getenv("TRAVIS_BUILD_DIR") != "" {
|
||||||
|
t.Skipf("Fails in travis with: addr_test.go:68: Address flags not set properly, got=0, expected=128")
|
||||||
|
}
|
||||||
|
// TODO: IFA_F_PERMANENT does not seem to be set by default on older kernels?
|
||||||
|
var address = &net.IPNet{IP: net.IPv4(127, 0, 0, 2), Mask: net.CIDRMask(24, 32)}
|
||||||
|
var peer = &net.IPNet{IP: net.IPv4(127, 0, 0, 3), Mask: net.CIDRMask(24, 32)}
|
||||||
|
var addrTests = []struct {
|
||||||
|
addr *Addr
|
||||||
|
expected *Addr
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
&Addr{IPNet: address},
|
||||||
|
&Addr{IPNet: address, Label: "lo", Scope: syscall.RT_SCOPE_UNIVERSE, Flags: syscall.IFA_F_PERMANENT},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Addr{IPNet: address, Label: "local"},
|
||||||
|
&Addr{IPNet: address, Label: "local", Scope: syscall.RT_SCOPE_UNIVERSE, Flags: syscall.IFA_F_PERMANENT},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Addr{IPNet: address, Flags: syscall.IFA_F_OPTIMISTIC},
|
||||||
|
&Addr{IPNet: address, Label: "lo", Flags: syscall.IFA_F_OPTIMISTIC | syscall.IFA_F_PERMANENT, Scope: syscall.RT_SCOPE_UNIVERSE},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Addr{IPNet: address, Flags: syscall.IFA_F_OPTIMISTIC | syscall.IFA_F_DADFAILED},
|
||||||
|
&Addr{IPNet: address, Label: "lo", Flags: syscall.IFA_F_OPTIMISTIC | syscall.IFA_F_DADFAILED | syscall.IFA_F_PERMANENT, Scope: syscall.RT_SCOPE_UNIVERSE},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Addr{IPNet: address, Scope: syscall.RT_SCOPE_NOWHERE},
|
||||||
|
&Addr{IPNet: address, Label: "lo", Flags: syscall.IFA_F_PERMANENT, Scope: syscall.RT_SCOPE_NOWHERE},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Addr{IPNet: address, Peer: peer},
|
||||||
|
&Addr{IPNet: address, Peer: peer, Label: "lo", Scope: syscall.RT_SCOPE_UNIVERSE, Flags: syscall.IFA_F_PERMANENT},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
link, err := LinkByName("lo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range addrTests {
|
||||||
|
if err = FunctionUndertest(link, tt.addr); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, err := AddrList(link, FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(addrs) != 1 {
|
||||||
|
t.Fatal("Address not added properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !addrs[0].Equal(*tt.expected) {
|
||||||
|
t.Fatalf("Address ip no set properly, got=%s, expected=%s", addrs[0], tt.expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
if addrs[0].Label != tt.expected.Label {
|
||||||
|
t.Fatalf("Address label not set properly, got=%s, expected=%s", addrs[0].Label, tt.expected.Label)
|
||||||
|
}
|
||||||
|
|
||||||
|
if addrs[0].Flags != tt.expected.Flags {
|
||||||
|
t.Fatalf("Address flags not set properly, got=%d, expected=%d", addrs[0].Flags, tt.expected.Flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
if addrs[0].Scope != tt.expected.Scope {
|
||||||
|
t.Fatalf("Address scope not set properly, got=%d, expected=%d", addrs[0].Scope, tt.expected.Scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.expected.Peer != nil {
|
||||||
|
if !addrs[0].PeerEqual(*tt.expected) {
|
||||||
|
t.Fatalf("Peer Address ip no set properly, got=%s, expected=%s", addrs[0].Peer, tt.expected.Peer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass FAMILY_V4, we should get the same results as FAMILY_ALL
|
||||||
|
addrs, err = AddrList(link, FAMILY_V4)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(addrs) != 1 {
|
||||||
|
t.Fatal("Address not added properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass a wrong family number, we should get nil list
|
||||||
|
addrs, err = AddrList(link, 0x8)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(addrs) != 0 {
|
||||||
|
t.Fatal("Address not expected")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = AddrDel(link, tt.addr); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, err = AddrList(link, FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(addrs) != 0 {
|
||||||
|
t.Fatal("Address not removed properly")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddrAddReplace(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
var address = &net.IPNet{IP: net.IPv4(127, 0, 0, 2), Mask: net.CIDRMask(24, 32)}
|
||||||
|
var addr = &Addr{IPNet: address}
|
||||||
|
|
||||||
|
link, err := LinkByName("lo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = AddrAdd(link, addr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, err := AddrList(link, FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(addrs) != 1 {
|
||||||
|
t.Fatal("Address not added properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = AddrAdd(link, addr)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Re-adding address should fail (but succeeded unexpectedly).")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = AddrReplace(link, addr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Replacing address failed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, err = AddrList(link, FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(addrs) != 1 {
|
||||||
|
t.Fatal("Address not added properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = AddrDel(link, addr); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, err = AddrList(link, FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(addrs) != 0 {
|
||||||
|
t.Fatal("Address not removed properly")
|
||||||
|
}
|
||||||
|
}
|
408
vendor/github.com/vishvananda/netlink/class_test.go
generated
vendored
Normal file
408
vendor/github.com/vishvananda/netlink/class_test.go
generated
vendored
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestClassAddDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
attrs := QdiscAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Handle: MakeHandle(0xffff, 0),
|
||||||
|
Parent: HANDLE_ROOT,
|
||||||
|
}
|
||||||
|
qdisc := NewHtb(attrs)
|
||||||
|
if err := QdiscAdd(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err := QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
_, ok := qdiscs[0].(*Htb)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
classattrs := ClassAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Parent: MakeHandle(0xffff, 0),
|
||||||
|
Handle: MakeHandle(0xffff, 2),
|
||||||
|
}
|
||||||
|
|
||||||
|
htbclassattrs := HtbClassAttrs{
|
||||||
|
Rate: 1234000,
|
||||||
|
Cbuffer: 1690,
|
||||||
|
}
|
||||||
|
class := NewHtbClass(classattrs, htbclassattrs)
|
||||||
|
if err := ClassAdd(class); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
classes, err := ClassList(link, MakeHandle(0xffff, 0))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(classes) != 1 {
|
||||||
|
t.Fatal("Failed to add class")
|
||||||
|
}
|
||||||
|
|
||||||
|
htb, ok := classes[0].(*HtbClass)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Class is the wrong type")
|
||||||
|
}
|
||||||
|
if htb.Rate != class.Rate {
|
||||||
|
t.Fatal("Rate doesn't match")
|
||||||
|
}
|
||||||
|
if htb.Ceil != class.Ceil {
|
||||||
|
t.Fatal("Ceil doesn't match")
|
||||||
|
}
|
||||||
|
if htb.Buffer != class.Buffer {
|
||||||
|
t.Fatal("Buffer doesn't match")
|
||||||
|
}
|
||||||
|
if htb.Cbuffer != class.Cbuffer {
|
||||||
|
t.Fatal("Cbuffer doesn't match")
|
||||||
|
}
|
||||||
|
|
||||||
|
qattrs := QdiscAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Handle: MakeHandle(0x2, 0),
|
||||||
|
Parent: MakeHandle(0xffff, 2),
|
||||||
|
}
|
||||||
|
nattrs := NetemQdiscAttrs{
|
||||||
|
Latency: 20000,
|
||||||
|
Loss: 23.4,
|
||||||
|
Duplicate: 14.3,
|
||||||
|
LossCorr: 8.34,
|
||||||
|
Jitter: 1000,
|
||||||
|
DelayCorr: 12.3,
|
||||||
|
ReorderProb: 23.4,
|
||||||
|
CorruptProb: 10.0,
|
||||||
|
CorruptCorr: 10,
|
||||||
|
}
|
||||||
|
qdiscnetem := NewNetem(qattrs, nattrs)
|
||||||
|
if err := QdiscAdd(qdiscnetem); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 2 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
_, ok = qdiscs[0].(*Htb)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
netem, ok := qdiscs[1].(*Netem)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
// Compare the record we got from the list with the one we created
|
||||||
|
if netem.Loss != qdiscnetem.Loss {
|
||||||
|
t.Fatal("Loss does not match")
|
||||||
|
}
|
||||||
|
if netem.Latency != qdiscnetem.Latency {
|
||||||
|
t.Fatal("Latency does not match")
|
||||||
|
}
|
||||||
|
if netem.CorruptProb != qdiscnetem.CorruptProb {
|
||||||
|
t.Fatal("CorruptProb does not match")
|
||||||
|
}
|
||||||
|
if netem.Jitter != qdiscnetem.Jitter {
|
||||||
|
t.Fatal("Jitter does not match")
|
||||||
|
}
|
||||||
|
if netem.LossCorr != qdiscnetem.LossCorr {
|
||||||
|
t.Fatal("Loss does not match")
|
||||||
|
}
|
||||||
|
if netem.DuplicateCorr != qdiscnetem.DuplicateCorr {
|
||||||
|
t.Fatal("DuplicateCorr does not match")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletion
|
||||||
|
if err := ClassDel(class); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
classes, err = ClassList(link, MakeHandle(0xffff, 0))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(classes) != 0 {
|
||||||
|
t.Fatal("Failed to remove class")
|
||||||
|
}
|
||||||
|
if err := QdiscDel(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 0 {
|
||||||
|
t.Fatal("Failed to remove qdisc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHtbClassAddHtbClassChangeDel(t *testing.T) {
|
||||||
|
/**
|
||||||
|
This test first set up a interface ans set up a Htb qdisc
|
||||||
|
A HTB class is attach to it and a Netem qdisc is attached to that class
|
||||||
|
Next, we test changing the HTB class in place and confirming the Netem is
|
||||||
|
still attached. We also check that invoting ClassChange with a non-existing
|
||||||
|
class will fail.
|
||||||
|
Finally, we test ClassReplace. We confirm it correctly behave like
|
||||||
|
ClassChange when the parent/handle pair exists and that it will create a
|
||||||
|
new class if the handle is modified.
|
||||||
|
*/
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
attrs := QdiscAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Handle: MakeHandle(0xffff, 0),
|
||||||
|
Parent: HANDLE_ROOT,
|
||||||
|
}
|
||||||
|
qdisc := NewHtb(attrs)
|
||||||
|
if err := QdiscAdd(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err := QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
_, ok := qdiscs[0].(*Htb)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
classattrs := ClassAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Parent: MakeHandle(0xffff, 0),
|
||||||
|
Handle: MakeHandle(0xffff, 2),
|
||||||
|
}
|
||||||
|
|
||||||
|
htbclassattrs := HtbClassAttrs{
|
||||||
|
Rate: 1234000,
|
||||||
|
Cbuffer: 1690,
|
||||||
|
}
|
||||||
|
class := NewHtbClass(classattrs, htbclassattrs)
|
||||||
|
if err := ClassAdd(class); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
classes, err := ClassList(link, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(classes) != 1 {
|
||||||
|
t.Fatal("Failed to add class")
|
||||||
|
}
|
||||||
|
|
||||||
|
htb, ok := classes[0].(*HtbClass)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Class is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
qattrs := QdiscAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Handle: MakeHandle(0x2, 0),
|
||||||
|
Parent: MakeHandle(0xffff, 2),
|
||||||
|
}
|
||||||
|
nattrs := NetemQdiscAttrs{
|
||||||
|
Latency: 20000,
|
||||||
|
Loss: 23.4,
|
||||||
|
Duplicate: 14.3,
|
||||||
|
LossCorr: 8.34,
|
||||||
|
Jitter: 1000,
|
||||||
|
DelayCorr: 12.3,
|
||||||
|
ReorderProb: 23.4,
|
||||||
|
CorruptProb: 10.0,
|
||||||
|
CorruptCorr: 10,
|
||||||
|
}
|
||||||
|
qdiscnetem := NewNetem(qattrs, nattrs)
|
||||||
|
if err := QdiscAdd(qdiscnetem); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 2 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok = qdiscs[1].(*Netem)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change
|
||||||
|
// For change to work, the handle and parent cannot be changed.
|
||||||
|
|
||||||
|
// First, test it fails if we change the Handle.
|
||||||
|
oldHandle := classattrs.Handle
|
||||||
|
classattrs.Handle = MakeHandle(0xffff, 3)
|
||||||
|
class = NewHtbClass(classattrs, htbclassattrs)
|
||||||
|
if err := ClassChange(class); err == nil {
|
||||||
|
t.Fatal("ClassChange should not work when using a different handle.")
|
||||||
|
}
|
||||||
|
// It should work with the same handle
|
||||||
|
classattrs.Handle = oldHandle
|
||||||
|
htbclassattrs.Rate = 4321000
|
||||||
|
class = NewHtbClass(classattrs, htbclassattrs)
|
||||||
|
if err := ClassChange(class); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
classes, err = ClassList(link, MakeHandle(0xffff, 0))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(classes) != 1 {
|
||||||
|
t.Fatalf(
|
||||||
|
"1 class expected, %d found",
|
||||||
|
len(classes),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
htb, ok = classes[0].(*HtbClass)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Class is the wrong type")
|
||||||
|
}
|
||||||
|
// Verify that the rate value has changed.
|
||||||
|
if htb.Rate != class.Rate {
|
||||||
|
t.Fatal("Rate did not get changed while changing the class.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that we still have the netem child qdisc
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(qdiscs) != 2 {
|
||||||
|
t.Fatalf("2 qdisc expected, %d found", len(qdiscs))
|
||||||
|
}
|
||||||
|
_, ok = qdiscs[0].(*Htb)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok = qdiscs[1].(*Netem)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace
|
||||||
|
// First replace by keeping the same handle, class will be changed.
|
||||||
|
// Then, replace by providing a new handle, n new class will be created.
|
||||||
|
|
||||||
|
// Replace acting as Change
|
||||||
|
class = NewHtbClass(classattrs, htbclassattrs)
|
||||||
|
if err := ClassReplace(class); err != nil {
|
||||||
|
t.Fatal("Failed to replace class that is existing.")
|
||||||
|
}
|
||||||
|
|
||||||
|
classes, err = ClassList(link, MakeHandle(0xffff, 0))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(classes) != 1 {
|
||||||
|
t.Fatalf(
|
||||||
|
"1 class expected, %d found",
|
||||||
|
len(classes),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
htb, ok = classes[0].(*HtbClass)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Class is the wrong type")
|
||||||
|
}
|
||||||
|
// Verify that the rate value has changed.
|
||||||
|
if htb.Rate != class.Rate {
|
||||||
|
t.Fatal("Rate did not get changed while changing the class.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// It should work with the same handle
|
||||||
|
classattrs.Handle = MakeHandle(0xffff, 3)
|
||||||
|
class = NewHtbClass(classattrs, htbclassattrs)
|
||||||
|
if err := ClassReplace(class); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
classes, err = ClassList(link, MakeHandle(0xffff, 0))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(classes) != 2 {
|
||||||
|
t.Fatalf(
|
||||||
|
"2 classes expected, %d found",
|
||||||
|
len(classes),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
htb, ok = classes[1].(*HtbClass)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Class is the wrong type")
|
||||||
|
}
|
||||||
|
// Verify that the rate value has changed.
|
||||||
|
if htb.Rate != class.Rate {
|
||||||
|
t.Fatal("Rate did not get changed while changing the class.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletion
|
||||||
|
for _, class := range classes {
|
||||||
|
if err := ClassDel(class); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
classes, err = ClassList(link, MakeHandle(0xffff, 0))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(classes) != 0 {
|
||||||
|
t.Fatal("Failed to remove class")
|
||||||
|
}
|
||||||
|
if err := QdiscDel(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 0 {
|
||||||
|
t.Fatal("Failed to remove qdisc")
|
||||||
|
}
|
||||||
|
}
|
344
vendor/github.com/vishvananda/netlink/conntrack_linux.go
generated
vendored
Normal file
344
vendor/github.com/vishvananda/netlink/conntrack_linux.go
generated
vendored
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/vishvananda/netlink/nl"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConntrackTableType Conntrack table for the netlink operation
|
||||||
|
type ConntrackTableType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ConntrackTable Conntrack table
|
||||||
|
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/netfilter/nfnetlink.h -> #define NFNL_SUBSYS_CTNETLINK 1
|
||||||
|
ConntrackTable = 1
|
||||||
|
// ConntrackExpectTable Conntrack expect table
|
||||||
|
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/netfilter/nfnetlink.h -> #define NFNL_SUBSYS_CTNETLINK_EXP 2
|
||||||
|
ConntrackExpectTable = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// backward compatibility with golang 1.6 which does not have io.SeekCurrent
|
||||||
|
seekCurrent = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// InetFamily Family type
|
||||||
|
type InetFamily uint8
|
||||||
|
|
||||||
|
// -L [table] [options] List conntrack or expectation table
|
||||||
|
// -G [table] parameters Get conntrack or expectation
|
||||||
|
|
||||||
|
// -I [table] parameters Create a conntrack or expectation
|
||||||
|
// -U [table] parameters Update a conntrack
|
||||||
|
// -E [table] [options] Show events
|
||||||
|
|
||||||
|
// -C [table] Show counter
|
||||||
|
// -S Show statistics
|
||||||
|
|
||||||
|
// ConntrackTableList returns the flow list of a table of a specific family
|
||||||
|
// conntrack -L [table] [options] List conntrack or expectation table
|
||||||
|
func ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
|
||||||
|
return pkgHandle.ConntrackTableList(table, family)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConntrackTableFlush flushes all the flows of a specified table
|
||||||
|
// conntrack -F [table] Flush table
|
||||||
|
// The flush operation applies to all the family types
|
||||||
|
func ConntrackTableFlush(table ConntrackTableType) error {
|
||||||
|
return pkgHandle.ConntrackTableFlush(table)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConntrackDeleteFilter deletes entries on the specified table on the base of the filter
|
||||||
|
// conntrack -D [table] parameters Delete conntrack or expectation
|
||||||
|
func ConntrackDeleteFilter(table ConntrackTableType, family InetFamily, filter *ConntrackFilter) (uint, error) {
|
||||||
|
return pkgHandle.ConntrackDeleteFilter(table, family, filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConntrackTableList returns the flow list of a table of a specific family using the netlink handle passed
|
||||||
|
// conntrack -L [table] [options] List conntrack or expectation table
|
||||||
|
func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
|
||||||
|
res, err := h.dumpConntrackTable(table, family)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize all the flows
|
||||||
|
var result []*ConntrackFlow
|
||||||
|
for _, dataRaw := range res {
|
||||||
|
result = append(result, parseRawData(dataRaw))
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConntrackTableFlush flushes all the flows of a specified table using the netlink handle passed
|
||||||
|
// conntrack -F [table] Flush table
|
||||||
|
// The flush operation applies to all the family types
|
||||||
|
func (h *Handle) ConntrackTableFlush(table ConntrackTableType) error {
|
||||||
|
req := h.newConntrackRequest(table, syscall.AF_INET, nl.IPCTNL_MSG_CT_DELETE, syscall.NLM_F_ACK)
|
||||||
|
_, err := req.Execute(syscall.NETLINK_NETFILTER, 0)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConntrackDeleteFilter deletes entries on the specified table on the base of the filter using the netlink handle passed
|
||||||
|
// conntrack -D [table] parameters Delete conntrack or expectation
|
||||||
|
func (h *Handle) ConntrackDeleteFilter(table ConntrackTableType, family InetFamily, filter *ConntrackFilter) (uint, error) {
|
||||||
|
res, err := h.dumpConntrackTable(table, family)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var matched uint
|
||||||
|
for _, dataRaw := range res {
|
||||||
|
flow := parseRawData(dataRaw)
|
||||||
|
if match := filter.MatchConntrackFlow(flow); match {
|
||||||
|
req2 := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_DELETE, syscall.NLM_F_ACK)
|
||||||
|
// skip the first 4 byte that are the netfilter header, the newConntrackRequest is adding it already
|
||||||
|
req2.AddRawData(dataRaw[4:])
|
||||||
|
req2.Execute(syscall.NETLINK_NETFILTER, 0)
|
||||||
|
matched++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matched, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) newConntrackRequest(table ConntrackTableType, family InetFamily, operation, flags int) *nl.NetlinkRequest {
|
||||||
|
// Create the Netlink request object
|
||||||
|
req := h.newNetlinkRequest((int(table)<<8)|operation, flags)
|
||||||
|
// Add the netfilter header
|
||||||
|
msg := &nl.Nfgenmsg{
|
||||||
|
NfgenFamily: uint8(family),
|
||||||
|
Version: nl.NFNETLINK_V0,
|
||||||
|
ResId: 0,
|
||||||
|
}
|
||||||
|
req.AddData(msg)
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) dumpConntrackTable(table ConntrackTableType, family InetFamily) ([][]byte, error) {
|
||||||
|
req := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_GET, syscall.NLM_F_DUMP)
|
||||||
|
return req.Execute(syscall.NETLINK_NETFILTER, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The full conntrack flow structure is very complicated and can be found in the file:
|
||||||
|
// http://git.netfilter.org/libnetfilter_conntrack/tree/include/internal/object.h
|
||||||
|
// For the time being, the structure below allows to parse and extract the base information of a flow
|
||||||
|
type ipTuple struct {
|
||||||
|
SrcIP net.IP
|
||||||
|
DstIP net.IP
|
||||||
|
Protocol uint8
|
||||||
|
SrcPort uint16
|
||||||
|
DstPort uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConntrackFlow struct {
|
||||||
|
FamilyType uint8
|
||||||
|
Forward ipTuple
|
||||||
|
Reverse ipTuple
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ConntrackFlow) String() string {
|
||||||
|
// conntrack cmd output:
|
||||||
|
// udp 17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001
|
||||||
|
return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d\tsrc=%s dst=%s sport=%d dport=%d",
|
||||||
|
nl.L4ProtoMap[s.Forward.Protocol], s.Forward.Protocol,
|
||||||
|
s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort,
|
||||||
|
s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method parse the ip tuple structure
|
||||||
|
// The message structure is the following:
|
||||||
|
// <len, [CTA_IP_V4_SRC|CTA_IP_V6_SRC], 16 bytes for the IP>
|
||||||
|
// <len, [CTA_IP_V4_DST|CTA_IP_V6_DST], 16 bytes for the IP>
|
||||||
|
// <len, NLA_F_NESTED|nl.CTA_TUPLE_PROTO, 1 byte for the protocol, 3 bytes of padding>
|
||||||
|
// <len, CTA_PROTO_SRC_PORT, 2 bytes for the source port, 2 bytes of padding>
|
||||||
|
// <len, CTA_PROTO_DST_PORT, 2 bytes for the source port, 2 bytes of padding>
|
||||||
|
func parseIpTuple(reader *bytes.Reader, tpl *ipTuple) {
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
_, t, _, v := parseNfAttrTLV(reader)
|
||||||
|
switch t {
|
||||||
|
case nl.CTA_IP_V4_SRC, nl.CTA_IP_V6_SRC:
|
||||||
|
tpl.SrcIP = v
|
||||||
|
case nl.CTA_IP_V4_DST, nl.CTA_IP_V6_DST:
|
||||||
|
tpl.DstIP = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Skip the next 4 bytes nl.NLA_F_NESTED|nl.CTA_TUPLE_PROTO
|
||||||
|
reader.Seek(4, seekCurrent)
|
||||||
|
_, t, _, v := parseNfAttrTLV(reader)
|
||||||
|
if t == nl.CTA_PROTO_NUM {
|
||||||
|
tpl.Protocol = uint8(v[0])
|
||||||
|
}
|
||||||
|
// Skip some padding 3 bytes
|
||||||
|
reader.Seek(3, seekCurrent)
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
_, t, _ := parseNfAttrTL(reader)
|
||||||
|
switch t {
|
||||||
|
case nl.CTA_PROTO_SRC_PORT:
|
||||||
|
parseBERaw16(reader, &tpl.SrcPort)
|
||||||
|
case nl.CTA_PROTO_DST_PORT:
|
||||||
|
parseBERaw16(reader, &tpl.DstPort)
|
||||||
|
}
|
||||||
|
// Skip some padding 2 byte
|
||||||
|
reader.Seek(2, seekCurrent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseNfAttrTLV(r *bytes.Reader) (isNested bool, attrType, len uint16, value []byte) {
|
||||||
|
isNested, attrType, len = parseNfAttrTL(r)
|
||||||
|
|
||||||
|
value = make([]byte, len)
|
||||||
|
binary.Read(r, binary.BigEndian, &value)
|
||||||
|
return isNested, attrType, len, value
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseNfAttrTL(r *bytes.Reader) (isNested bool, attrType, len uint16) {
|
||||||
|
binary.Read(r, nl.NativeEndian(), &len)
|
||||||
|
len -= nl.SizeofNfattr
|
||||||
|
|
||||||
|
binary.Read(r, nl.NativeEndian(), &attrType)
|
||||||
|
isNested = (attrType & nl.NLA_F_NESTED) == nl.NLA_F_NESTED
|
||||||
|
attrType = attrType & (nl.NLA_F_NESTED - 1)
|
||||||
|
|
||||||
|
return isNested, attrType, len
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseBERaw16(r *bytes.Reader, v *uint16) {
|
||||||
|
binary.Read(r, binary.BigEndian, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRawData(data []byte) *ConntrackFlow {
|
||||||
|
s := &ConntrackFlow{}
|
||||||
|
// First there is the Nfgenmsg header
|
||||||
|
// consume only the family field
|
||||||
|
reader := bytes.NewReader(data)
|
||||||
|
binary.Read(reader, nl.NativeEndian(), &s.FamilyType)
|
||||||
|
|
||||||
|
// skip rest of the Netfilter header
|
||||||
|
reader.Seek(3, seekCurrent)
|
||||||
|
// The message structure is the following:
|
||||||
|
// <len, NLA_F_NESTED|CTA_TUPLE_ORIG> 4 bytes
|
||||||
|
// <len, NLA_F_NESTED|CTA_TUPLE_IP> 4 bytes
|
||||||
|
// flow information of the forward flow
|
||||||
|
// <len, NLA_F_NESTED|CTA_TUPLE_REPLY> 4 bytes
|
||||||
|
// <len, NLA_F_NESTED|CTA_TUPLE_IP> 4 bytes
|
||||||
|
// flow information of the reverse flow
|
||||||
|
for reader.Len() > 0 {
|
||||||
|
nested, t, l := parseNfAttrTL(reader)
|
||||||
|
if nested && t == nl.CTA_TUPLE_ORIG {
|
||||||
|
if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
|
||||||
|
parseIpTuple(reader, &s.Forward)
|
||||||
|
}
|
||||||
|
} else if nested && t == nl.CTA_TUPLE_REPLY {
|
||||||
|
if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
|
||||||
|
parseIpTuple(reader, &s.Reverse)
|
||||||
|
|
||||||
|
// Got all the useful information stop parsing
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
// Header not recognized skip it
|
||||||
|
reader.Seek(int64(l), seekCurrent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conntrack parameters and options:
|
||||||
|
// -n, --src-nat ip source NAT ip
|
||||||
|
// -g, --dst-nat ip destination NAT ip
|
||||||
|
// -j, --any-nat ip source or destination NAT ip
|
||||||
|
// -m, --mark mark Set mark
|
||||||
|
// -c, --secmark secmark Set selinux secmark
|
||||||
|
// -e, --event-mask eventmask Event mask, eg. NEW,DESTROY
|
||||||
|
// -z, --zero Zero counters while listing
|
||||||
|
// -o, --output type[,...] Output format, eg. xml
|
||||||
|
// -l, --label label[,...] conntrack labels
|
||||||
|
|
||||||
|
// Common parameters and options:
|
||||||
|
// -s, --src, --orig-src ip Source address from original direction
|
||||||
|
// -d, --dst, --orig-dst ip Destination address from original direction
|
||||||
|
// -r, --reply-src ip Source addres from reply direction
|
||||||
|
// -q, --reply-dst ip Destination address from reply direction
|
||||||
|
// -p, --protonum proto Layer 4 Protocol, eg. 'tcp'
|
||||||
|
// -f, --family proto Layer 3 Protocol, eg. 'ipv6'
|
||||||
|
// -t, --timeout timeout Set timeout
|
||||||
|
// -u, --status status Set status, eg. ASSURED
|
||||||
|
// -w, --zone value Set conntrack zone
|
||||||
|
// --orig-zone value Set zone for original direction
|
||||||
|
// --reply-zone value Set zone for reply direction
|
||||||
|
// -b, --buffer-size Netlink socket buffer size
|
||||||
|
// --mask-src ip Source mask address
|
||||||
|
// --mask-dst ip Destination mask address
|
||||||
|
|
||||||
|
// Filter types
|
||||||
|
type ConntrackFilterType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
ConntrackOrigSrcIP = iota // -orig-src ip Source address from original direction
|
||||||
|
ConntrackOrigDstIP // -orig-dst ip Destination address from original direction
|
||||||
|
ConntrackNatSrcIP // -src-nat ip Source NAT ip
|
||||||
|
ConntrackNatDstIP // -dst-nat ip Destination NAT ip
|
||||||
|
ConntrackNatAnyIP // -any-nat ip Source or destination NAT ip
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConntrackFilter struct {
|
||||||
|
ipFilter map[ConntrackFilterType]net.IP
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddIP adds an IP to the conntrack filter
|
||||||
|
func (f *ConntrackFilter) AddIP(tp ConntrackFilterType, ip net.IP) error {
|
||||||
|
if f.ipFilter == nil {
|
||||||
|
f.ipFilter = make(map[ConntrackFilterType]net.IP)
|
||||||
|
}
|
||||||
|
if _, ok := f.ipFilter[tp]; ok {
|
||||||
|
return errors.New("Filter attribute already present")
|
||||||
|
}
|
||||||
|
f.ipFilter[tp] = ip
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchConntrackFlow applies the filter to the flow and returns true if the flow matches the filter
|
||||||
|
// false otherwise
|
||||||
|
func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool {
|
||||||
|
if len(f.ipFilter) == 0 {
|
||||||
|
// empty filter always not match
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
match := true
|
||||||
|
// -orig-src ip Source address from original direction
|
||||||
|
if elem, found := f.ipFilter[ConntrackOrigSrcIP]; found {
|
||||||
|
match = match && elem.Equal(flow.Forward.SrcIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -orig-dst ip Destination address from original direction
|
||||||
|
if elem, found := f.ipFilter[ConntrackOrigDstIP]; match && found {
|
||||||
|
match = match && elem.Equal(flow.Forward.DstIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -src-nat ip Source NAT ip
|
||||||
|
if elem, found := f.ipFilter[ConntrackNatSrcIP]; match && found {
|
||||||
|
match = match && elem.Equal(flow.Reverse.SrcIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -dst-nat ip Destination NAT ip
|
||||||
|
if elem, found := f.ipFilter[ConntrackNatDstIP]; match && found {
|
||||||
|
match = match && elem.Equal(flow.Reverse.DstIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -any-nat ip Source or destination NAT ip
|
||||||
|
if elem, found := f.ipFilter[ConntrackNatAnyIP]; match && found {
|
||||||
|
match = match && (elem.Equal(flow.Reverse.SrcIP) || elem.Equal(flow.Reverse.DstIP))
|
||||||
|
}
|
||||||
|
|
||||||
|
return match
|
||||||
|
}
|
387
vendor/github.com/vishvananda/netlink/conntrack_test.go
generated
vendored
Normal file
387
vendor/github.com/vishvananda/netlink/conntrack_test.go
generated
vendored
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"runtime"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/vishvananda/netns"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CheckErrorFail(t *testing.T, err error) {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Fatal Error: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func CheckError(t *testing.T, err error) {
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func udpFlowCreateProg(t *testing.T, flows, srcPort int, dstIP string, dstPort int) {
|
||||||
|
for i := 0; i < flows; i++ {
|
||||||
|
ServerAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", dstIP, dstPort))
|
||||||
|
CheckError(t, err)
|
||||||
|
|
||||||
|
LocalAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("127.0.0.1:%d", srcPort+i))
|
||||||
|
CheckError(t, err)
|
||||||
|
|
||||||
|
Conn, err := net.DialUDP("udp", LocalAddr, ServerAddr)
|
||||||
|
CheckError(t, err)
|
||||||
|
|
||||||
|
Conn.Write([]byte("Hello World"))
|
||||||
|
Conn.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func nsCreateAndEnter(t *testing.T) (*netns.NsHandle, *netns.NsHandle, *Handle) {
|
||||||
|
// Lock the OS Thread so we don't accidentally switch namespaces
|
||||||
|
runtime.LockOSThread()
|
||||||
|
|
||||||
|
// Save the current network namespace
|
||||||
|
origns, _ := netns.Get()
|
||||||
|
|
||||||
|
ns, err := netns.New()
|
||||||
|
CheckErrorFail(t, err)
|
||||||
|
|
||||||
|
h, err := NewHandleAt(ns)
|
||||||
|
CheckErrorFail(t, err)
|
||||||
|
|
||||||
|
// Enter the new namespace
|
||||||
|
netns.Set(ns)
|
||||||
|
|
||||||
|
// Bing up loopback
|
||||||
|
link, _ := h.LinkByName("lo")
|
||||||
|
h.LinkSetUp(link)
|
||||||
|
|
||||||
|
return &origns, &ns, h
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyFilter(flowList []ConntrackFlow, ipv4Filter *ConntrackFilter, ipv6Filter *ConntrackFilter) (ipv4Match, ipv6Match uint) {
|
||||||
|
for _, flow := range flowList {
|
||||||
|
if ipv4Filter.MatchConntrackFlow(&flow) == true {
|
||||||
|
ipv4Match++
|
||||||
|
}
|
||||||
|
if ipv6Filter.MatchConntrackFlow(&flow) == true {
|
||||||
|
ipv6Match++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ipv4Match, ipv6Match
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestConntrackSocket test the opening of a NETFILTER family socket
|
||||||
|
func TestConntrackSocket(t *testing.T) {
|
||||||
|
skipUnlessRoot(t)
|
||||||
|
|
||||||
|
h, err := NewHandle(syscall.NETLINK_NETFILTER)
|
||||||
|
CheckErrorFail(t, err)
|
||||||
|
|
||||||
|
if h.SupportsNetlinkFamily(syscall.NETLINK_NETFILTER) != true {
|
||||||
|
t.Fatal("ERROR not supporting the NETFILTER family")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestConntrackTableList test the conntrack table list
|
||||||
|
// Creates some flows and checks that they are correctly fetched from the conntrack table
|
||||||
|
func TestConntrackTableList(t *testing.T) {
|
||||||
|
skipUnlessRoot(t)
|
||||||
|
|
||||||
|
// Creates a new namespace and bring up the loopback interface
|
||||||
|
origns, ns, h := nsCreateAndEnter(t)
|
||||||
|
defer netns.Set(*origns)
|
||||||
|
defer origns.Close()
|
||||||
|
defer ns.Close()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
// Flush the table to start fresh
|
||||||
|
err := h.ConntrackTableFlush(ConntrackTable)
|
||||||
|
CheckErrorFail(t, err)
|
||||||
|
|
||||||
|
// Create 5 udp
|
||||||
|
udpFlowCreateProg(t, 5, 2000, "127.0.0.10", 3000)
|
||||||
|
|
||||||
|
// Fetch the conntrack table
|
||||||
|
flows, err := h.ConntrackTableList(ConntrackTable, syscall.AF_INET)
|
||||||
|
CheckErrorFail(t, err)
|
||||||
|
|
||||||
|
// Check that it is able to find the 5 flows created
|
||||||
|
var found int
|
||||||
|
for _, flow := range flows {
|
||||||
|
if flow.Forward.Protocol == 17 &&
|
||||||
|
flow.Forward.DstIP.Equal(net.ParseIP("127.0.0.10")) &&
|
||||||
|
flow.Forward.DstPort == 3000 &&
|
||||||
|
(flow.Forward.SrcPort >= 2000 && flow.Forward.SrcPort <= 2005) {
|
||||||
|
found++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found != 5 {
|
||||||
|
t.Fatalf("Found only %d flows over 5", found)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give a try also to the IPv6 version
|
||||||
|
_, err = h.ConntrackTableList(ConntrackTable, syscall.AF_INET6)
|
||||||
|
CheckErrorFail(t, err)
|
||||||
|
|
||||||
|
// Switch back to the original namespace
|
||||||
|
netns.Set(*origns)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestConntrackTableFlush test the conntrack table flushing
|
||||||
|
// Creates some flows and then call the table flush
|
||||||
|
func TestConntrackTableFlush(t *testing.T) {
|
||||||
|
skipUnlessRoot(t)
|
||||||
|
|
||||||
|
// Creates a new namespace and bring up the loopback interface
|
||||||
|
origns, ns, h := nsCreateAndEnter(t)
|
||||||
|
defer netns.Set(*origns)
|
||||||
|
defer origns.Close()
|
||||||
|
defer ns.Close()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
// Create 5 udp flows using netcat
|
||||||
|
udpFlowCreateProg(t, 5, 3000, "127.0.0.10", 4000)
|
||||||
|
|
||||||
|
// Fetch the conntrack table
|
||||||
|
flows, err := h.ConntrackTableList(ConntrackTable, syscall.AF_INET)
|
||||||
|
CheckErrorFail(t, err)
|
||||||
|
|
||||||
|
// Check that it is able to find the 5 flows created
|
||||||
|
var found int
|
||||||
|
for _, flow := range flows {
|
||||||
|
if flow.Forward.Protocol == 17 &&
|
||||||
|
flow.Forward.DstIP.Equal(net.ParseIP("127.0.0.10")) &&
|
||||||
|
flow.Forward.DstPort == 4000 &&
|
||||||
|
(flow.Forward.SrcPort >= 3000 && flow.Forward.SrcPort <= 3005) {
|
||||||
|
found++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found != 5 {
|
||||||
|
t.Fatalf("Found only %d flows over 5", found)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush the table
|
||||||
|
err = h.ConntrackTableFlush(ConntrackTable)
|
||||||
|
CheckErrorFail(t, err)
|
||||||
|
|
||||||
|
// Fetch again the flows to validate the flush
|
||||||
|
flows, err = h.ConntrackTableList(ConntrackTable, syscall.AF_INET)
|
||||||
|
CheckErrorFail(t, err)
|
||||||
|
|
||||||
|
// Check if it is still able to find the 5 flows created
|
||||||
|
found = 0
|
||||||
|
for _, flow := range flows {
|
||||||
|
if flow.Forward.Protocol == 17 &&
|
||||||
|
flow.Forward.DstIP.Equal(net.ParseIP("127.0.0.10")) &&
|
||||||
|
flow.Forward.DstPort == 4000 &&
|
||||||
|
(flow.Forward.SrcPort >= 3000 && flow.Forward.SrcPort <= 3005) {
|
||||||
|
found++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found > 0 {
|
||||||
|
t.Fatalf("Found %d flows, they should had been flushed", found)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch back to the original namespace
|
||||||
|
netns.Set(*origns)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestConntrackTableDelete tests the deletion with filter
|
||||||
|
// Creates 2 group of flows then deletes only one group and validates the result
|
||||||
|
func TestConntrackTableDelete(t *testing.T) {
|
||||||
|
skipUnlessRoot(t)
|
||||||
|
|
||||||
|
// Creates a new namespace and bring up the loopback interface
|
||||||
|
origns, ns, h := nsCreateAndEnter(t)
|
||||||
|
defer netns.Set(*origns)
|
||||||
|
defer origns.Close()
|
||||||
|
defer ns.Close()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
// Create 10 udp flows
|
||||||
|
udpFlowCreateProg(t, 5, 5000, "127.0.0.10", 6000)
|
||||||
|
udpFlowCreateProg(t, 5, 7000, "127.0.0.20", 8000)
|
||||||
|
|
||||||
|
// Fetch the conntrack table
|
||||||
|
flows, err := h.ConntrackTableList(ConntrackTable, syscall.AF_INET)
|
||||||
|
CheckErrorFail(t, err)
|
||||||
|
|
||||||
|
// Check that it is able to find the 5 flows created for each group
|
||||||
|
var groupA int
|
||||||
|
var groupB int
|
||||||
|
for _, flow := range flows {
|
||||||
|
if flow.Forward.Protocol == 17 &&
|
||||||
|
flow.Forward.DstIP.Equal(net.ParseIP("127.0.0.10")) &&
|
||||||
|
flow.Forward.DstPort == 6000 &&
|
||||||
|
(flow.Forward.SrcPort >= 5000 && flow.Forward.SrcPort <= 5005) {
|
||||||
|
groupA++
|
||||||
|
}
|
||||||
|
if flow.Forward.Protocol == 17 &&
|
||||||
|
flow.Forward.DstIP.Equal(net.ParseIP("127.0.0.20")) &&
|
||||||
|
flow.Forward.DstPort == 8000 &&
|
||||||
|
(flow.Forward.SrcPort >= 7000 && flow.Forward.SrcPort <= 7005) {
|
||||||
|
groupB++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if groupA != 5 || groupB != 5 {
|
||||||
|
t.Fatalf("Flow creation issue groupA:%d, groupB:%d", groupA, groupB)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a filter to erase groupB flows
|
||||||
|
filter := &ConntrackFilter{}
|
||||||
|
filter.AddIP(ConntrackOrigDstIP, net.ParseIP("127.0.0.20"))
|
||||||
|
|
||||||
|
// Flush entries of groupB
|
||||||
|
var deleted uint
|
||||||
|
if deleted, err = h.ConntrackDeleteFilter(ConntrackTable, syscall.AF_INET, filter); err != nil {
|
||||||
|
t.Fatalf("Error during the erase: %s", err)
|
||||||
|
}
|
||||||
|
if deleted != 5 {
|
||||||
|
t.Fatalf("Error deleted a wrong number of flows:%d instead of 5", deleted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check again the table to verify that are gone
|
||||||
|
flows, err = h.ConntrackTableList(ConntrackTable, syscall.AF_INET)
|
||||||
|
CheckErrorFail(t, err)
|
||||||
|
|
||||||
|
// Check if it is able to find the 5 flows of groupA but none of groupB
|
||||||
|
groupA = 0
|
||||||
|
groupB = 0
|
||||||
|
for _, flow := range flows {
|
||||||
|
if flow.Forward.Protocol == 17 &&
|
||||||
|
flow.Forward.DstIP.Equal(net.ParseIP("127.0.0.10")) &&
|
||||||
|
flow.Forward.DstPort == 6000 &&
|
||||||
|
(flow.Forward.SrcPort >= 5000 && flow.Forward.SrcPort <= 5005) {
|
||||||
|
groupA++
|
||||||
|
}
|
||||||
|
if flow.Forward.Protocol == 17 &&
|
||||||
|
flow.Forward.DstIP.Equal(net.ParseIP("127.0.0.20")) &&
|
||||||
|
flow.Forward.DstPort == 8000 &&
|
||||||
|
(flow.Forward.SrcPort >= 7000 && flow.Forward.SrcPort <= 7005) {
|
||||||
|
groupB++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if groupA != 5 || groupB > 0 {
|
||||||
|
t.Fatalf("Error during the erase groupA:%d, groupB:%d", groupA, groupB)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch back to the original namespace
|
||||||
|
netns.Set(*origns)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConntrackFilter(t *testing.T) {
|
||||||
|
var flowList []ConntrackFlow
|
||||||
|
flowList = append(flowList, ConntrackFlow{
|
||||||
|
FamilyType: syscall.AF_INET,
|
||||||
|
Forward: ipTuple{
|
||||||
|
SrcIP: net.ParseIP("10.0.0.1"),
|
||||||
|
DstIP: net.ParseIP("20.0.0.1"),
|
||||||
|
SrcPort: 1000,
|
||||||
|
DstPort: 2000,
|
||||||
|
},
|
||||||
|
Reverse: ipTuple{
|
||||||
|
SrcIP: net.ParseIP("20.0.0.1"),
|
||||||
|
DstIP: net.ParseIP("192.168.1.1"),
|
||||||
|
SrcPort: 2000,
|
||||||
|
DstPort: 1000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ConntrackFlow{
|
||||||
|
FamilyType: syscall.AF_INET,
|
||||||
|
Forward: ipTuple{
|
||||||
|
SrcIP: net.ParseIP("10.0.0.2"),
|
||||||
|
DstIP: net.ParseIP("20.0.0.2"),
|
||||||
|
SrcPort: 5000,
|
||||||
|
DstPort: 6000,
|
||||||
|
},
|
||||||
|
Reverse: ipTuple{
|
||||||
|
SrcIP: net.ParseIP("20.0.0.2"),
|
||||||
|
DstIP: net.ParseIP("192.168.1.1"),
|
||||||
|
SrcPort: 6000,
|
||||||
|
DstPort: 5000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ConntrackFlow{
|
||||||
|
FamilyType: syscall.AF_INET6,
|
||||||
|
Forward: ipTuple{
|
||||||
|
SrcIP: net.ParseIP("eeee:eeee:eeee:eeee:eeee:eeee:eeee:eeee"),
|
||||||
|
DstIP: net.ParseIP("dddd:dddd:dddd:dddd:dddd:dddd:dddd:dddd"),
|
||||||
|
SrcPort: 1000,
|
||||||
|
DstPort: 2000,
|
||||||
|
},
|
||||||
|
Reverse: ipTuple{
|
||||||
|
SrcIP: net.ParseIP("dddd:dddd:dddd:dddd:dddd:dddd:dddd:dddd"),
|
||||||
|
DstIP: net.ParseIP("eeee:eeee:eeee:eeee:eeee:eeee:eeee:eeee"),
|
||||||
|
SrcPort: 2000,
|
||||||
|
DstPort: 1000,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Empty filter
|
||||||
|
v4Match, v6Match := applyFilter(flowList, &ConntrackFilter{}, &ConntrackFilter{})
|
||||||
|
if v4Match > 0 || v6Match > 0 {
|
||||||
|
t.Fatalf("Error, empty filter cannot match, v4:%d, v6:%d", v4Match, v6Match)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SrcIP filter
|
||||||
|
filterV4 := &ConntrackFilter{}
|
||||||
|
filterV4.AddIP(ConntrackOrigSrcIP, net.ParseIP("10.0.0.1"))
|
||||||
|
|
||||||
|
filterV6 := &ConntrackFilter{}
|
||||||
|
filterV6.AddIP(ConntrackOrigSrcIP, net.ParseIP("eeee:eeee:eeee:eeee:eeee:eeee:eeee:eeee"))
|
||||||
|
|
||||||
|
v4Match, v6Match = applyFilter(flowList, filterV4, filterV6)
|
||||||
|
if v4Match != 1 || v6Match != 1 {
|
||||||
|
t.Fatalf("Error, there should be only 1 match, v4:%d, v6:%d", v4Match, v6Match)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DstIp filter
|
||||||
|
filterV4 = &ConntrackFilter{}
|
||||||
|
filterV4.AddIP(ConntrackOrigDstIP, net.ParseIP("20.0.0.1"))
|
||||||
|
|
||||||
|
filterV6 = &ConntrackFilter{}
|
||||||
|
filterV6.AddIP(ConntrackOrigDstIP, net.ParseIP("dddd:dddd:dddd:dddd:dddd:dddd:dddd:dddd"))
|
||||||
|
|
||||||
|
v4Match, v6Match = applyFilter(flowList, filterV4, filterV6)
|
||||||
|
if v4Match != 1 || v6Match != 1 {
|
||||||
|
t.Fatalf("Error, there should be only 1 match, v4:%d, v6:%d", v4Match, v6Match)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SrcIP for NAT
|
||||||
|
filterV4 = &ConntrackFilter{}
|
||||||
|
filterV4.AddIP(ConntrackNatSrcIP, net.ParseIP("20.0.0.1"))
|
||||||
|
|
||||||
|
filterV6 = &ConntrackFilter{}
|
||||||
|
filterV6.AddIP(ConntrackNatSrcIP, net.ParseIP("dddd:dddd:dddd:dddd:dddd:dddd:dddd:dddd"))
|
||||||
|
|
||||||
|
v4Match, v6Match = applyFilter(flowList, filterV4, filterV6)
|
||||||
|
if v4Match != 1 || v6Match != 1 {
|
||||||
|
t.Fatalf("Error, there should be only 1 match, v4:%d, v6:%d", v4Match, v6Match)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DstIP for NAT
|
||||||
|
filterV4 = &ConntrackFilter{}
|
||||||
|
filterV4.AddIP(ConntrackNatDstIP, net.ParseIP("192.168.1.1"))
|
||||||
|
|
||||||
|
filterV6 = &ConntrackFilter{}
|
||||||
|
filterV6.AddIP(ConntrackNatDstIP, net.ParseIP("dddd:dddd:dddd:dddd:dddd:dddd:dddd:dddd"))
|
||||||
|
|
||||||
|
v4Match, v6Match = applyFilter(flowList, filterV4, filterV6)
|
||||||
|
if v4Match != 2 || v6Match != 0 {
|
||||||
|
t.Fatalf("Error, there should be an exact match, v4:%d, v6:%d", v4Match, v6Match)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnyIp for Nat
|
||||||
|
filterV4 = &ConntrackFilter{}
|
||||||
|
filterV4.AddIP(ConntrackNatAnyIP, net.ParseIP("192.168.1.1"))
|
||||||
|
|
||||||
|
filterV6 = &ConntrackFilter{}
|
||||||
|
filterV6.AddIP(ConntrackNatAnyIP, net.ParseIP("eeee:eeee:eeee:eeee:eeee:eeee:eeee:eeee"))
|
||||||
|
|
||||||
|
v4Match, v6Match = applyFilter(flowList, filterV4, filterV6)
|
||||||
|
if v4Match != 2 || v6Match != 1 {
|
||||||
|
t.Fatalf("Error, there should be an exact match, v4:%d, v6:%d", v4Match, v6Match)
|
||||||
|
}
|
||||||
|
}
|
53
vendor/github.com/vishvananda/netlink/conntrack_unspecified.go
generated
vendored
Normal file
53
vendor/github.com/vishvananda/netlink/conntrack_unspecified.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// +build !linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
// ConntrackTableType Conntrack table for the netlink operation
|
||||||
|
type ConntrackTableType uint8
|
||||||
|
|
||||||
|
// InetFamily Family type
|
||||||
|
type InetFamily uint8
|
||||||
|
|
||||||
|
// ConntrackFlow placeholder
|
||||||
|
type ConntrackFlow struct{}
|
||||||
|
|
||||||
|
// ConntrackFilter placeholder
|
||||||
|
type ConntrackFilter struct{}
|
||||||
|
|
||||||
|
// ConntrackTableList returns the flow list of a table of a specific family
|
||||||
|
// conntrack -L [table] [options] List conntrack or expectation table
|
||||||
|
func ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
|
||||||
|
return nil, ErrNotImplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConntrackTableFlush flushes all the flows of a specified table
|
||||||
|
// conntrack -F [table] Flush table
|
||||||
|
// The flush operation applies to all the family types
|
||||||
|
func ConntrackTableFlush(table ConntrackTableType) error {
|
||||||
|
return ErrNotImplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConntrackDeleteFilter deletes entries on the specified table on the base of the filter
|
||||||
|
// conntrack -D [table] parameters Delete conntrack or expectation
|
||||||
|
func ConntrackDeleteFilter(table ConntrackTableType, family InetFamily, filter *ConntrackFilter) (uint, error) {
|
||||||
|
return 0, ErrNotImplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConntrackTableList returns the flow list of a table of a specific family using the netlink handle passed
|
||||||
|
// conntrack -L [table] [options] List conntrack or expectation table
|
||||||
|
func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
|
||||||
|
return nil, ErrNotImplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConntrackTableFlush flushes all the flows of a specified table using the netlink handle passed
|
||||||
|
// conntrack -F [table] Flush table
|
||||||
|
// The flush operation applies to all the family types
|
||||||
|
func (h *Handle) ConntrackTableFlush(table ConntrackTableType) error {
|
||||||
|
return ErrNotImplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConntrackDeleteFilter deletes entries on the specified table on the base of the filter using the netlink handle passed
|
||||||
|
// conntrack -D [table] parameters Delete conntrack or expectation
|
||||||
|
func (h *Handle) ConntrackDeleteFilter(table ConntrackTableType, family InetFamily, filter *ConntrackFilter) (uint, error) {
|
||||||
|
return 0, ErrNotImplemented
|
||||||
|
}
|
41
vendor/github.com/vishvananda/netlink/filter.go
generated
vendored
41
vendor/github.com/vishvananda/netlink/filter.go
generated
vendored
@ -1,6 +1,10 @@
|
|||||||
package netlink
|
package netlink
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/vishvananda/netlink/nl"
|
||||||
|
)
|
||||||
|
|
||||||
type Filter interface {
|
type Filter interface {
|
||||||
Attrs() *FilterAttrs
|
Attrs() *FilterAttrs
|
||||||
@ -180,11 +184,46 @@ func NewMirredAction(redirIndex int) *MirredAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Constants used in TcU32Sel.Flags.
|
||||||
|
const (
|
||||||
|
TC_U32_TERMINAL = nl.TC_U32_TERMINAL
|
||||||
|
TC_U32_OFFSET = nl.TC_U32_OFFSET
|
||||||
|
TC_U32_VAROFFSET = nl.TC_U32_VAROFFSET
|
||||||
|
TC_U32_EAT = nl.TC_U32_EAT
|
||||||
|
)
|
||||||
|
|
||||||
|
// Sel of the U32 filters that contains multiple TcU32Key. This is the copy
|
||||||
|
// and the frontend representation of nl.TcU32Sel. It is serialized into canonical
|
||||||
|
// nl.TcU32Sel with the appropriate endianness.
|
||||||
|
type TcU32Sel struct {
|
||||||
|
Flags uint8
|
||||||
|
Offshift uint8
|
||||||
|
Nkeys uint8
|
||||||
|
Pad uint8
|
||||||
|
Offmask uint16
|
||||||
|
Off uint16
|
||||||
|
Offoff int16
|
||||||
|
Hoff int16
|
||||||
|
Hmask uint32
|
||||||
|
Keys []TcU32Key
|
||||||
|
}
|
||||||
|
|
||||||
|
// TcU32Key contained of Sel in the U32 filters. This is the copy and the frontend
|
||||||
|
// representation of nl.TcU32Key. It is serialized into chanonical nl.TcU32Sel
|
||||||
|
// with the appropriate endianness.
|
||||||
|
type TcU32Key struct {
|
||||||
|
Mask uint32
|
||||||
|
Val uint32
|
||||||
|
Off int32
|
||||||
|
OffMask int32
|
||||||
|
}
|
||||||
|
|
||||||
// U32 filters on many packet related properties
|
// U32 filters on many packet related properties
|
||||||
type U32 struct {
|
type U32 struct {
|
||||||
FilterAttrs
|
FilterAttrs
|
||||||
ClassId uint32
|
ClassId uint32
|
||||||
RedirIndex int
|
RedirIndex int
|
||||||
|
Sel *TcU32Sel
|
||||||
Actions []Action
|
Actions []Action
|
||||||
}
|
}
|
||||||
|
|
||||||
|
47
vendor/github.com/vishvananda/netlink/filter_linux.go
generated
vendored
47
vendor/github.com/vishvananda/netlink/filter_linux.go
generated
vendored
@ -6,6 +6,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/vishvananda/netlink/nl"
|
"github.com/vishvananda/netlink/nl"
|
||||||
)
|
)
|
||||||
@ -128,12 +129,34 @@ func (h *Handle) FilterAdd(filter Filter) error {
|
|||||||
|
|
||||||
options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
|
options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
|
||||||
if u32, ok := filter.(*U32); ok {
|
if u32, ok := filter.(*U32); ok {
|
||||||
// match all
|
// Convert TcU32Sel into nl.TcU32Sel as it is without copy.
|
||||||
sel := nl.TcU32Sel{
|
sel := (*nl.TcU32Sel)(unsafe.Pointer(u32.Sel))
|
||||||
Nkeys: 1,
|
if sel == nil {
|
||||||
Flags: nl.TC_U32_TERMINAL,
|
// match all
|
||||||
|
sel = &nl.TcU32Sel{
|
||||||
|
Nkeys: 1,
|
||||||
|
Flags: nl.TC_U32_TERMINAL,
|
||||||
|
}
|
||||||
|
sel.Keys = append(sel.Keys, nl.TcU32Key{})
|
||||||
}
|
}
|
||||||
sel.Keys = append(sel.Keys, nl.TcU32Key{})
|
|
||||||
|
if native != networkOrder {
|
||||||
|
// Copy Tcu32Sel.
|
||||||
|
cSel := sel
|
||||||
|
keys := make([]nl.TcU32Key, cap(sel.Keys))
|
||||||
|
copy(keys, sel.Keys)
|
||||||
|
cSel.Keys = keys
|
||||||
|
sel = cSel
|
||||||
|
|
||||||
|
// Handle the endianness of attributes
|
||||||
|
sel.Offmask = native.Uint16(htons(sel.Offmask))
|
||||||
|
sel.Hmask = native.Uint32(htonl(sel.Hmask))
|
||||||
|
for _, key := range sel.Keys {
|
||||||
|
key.Mask = native.Uint32(htonl(key.Mask))
|
||||||
|
key.Val = native.Uint32(htonl(key.Val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sel.Nkeys = uint8(len(sel.Keys))
|
||||||
nl.NewRtAttrChild(options, nl.TCA_U32_SEL, sel.Serialize())
|
nl.NewRtAttrChild(options, nl.TCA_U32_SEL, sel.Serialize())
|
||||||
if u32.ClassId != 0 {
|
if u32.ClassId != 0 {
|
||||||
nl.NewRtAttrChild(options, nl.TCA_U32_CLASSID, nl.Uint32Attr(u32.ClassId))
|
nl.NewRtAttrChild(options, nl.TCA_U32_CLASSID, nl.Uint32Attr(u32.ClassId))
|
||||||
@ -425,9 +448,15 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
|
|||||||
case nl.TCA_U32_SEL:
|
case nl.TCA_U32_SEL:
|
||||||
detailed = true
|
detailed = true
|
||||||
sel := nl.DeserializeTcU32Sel(datum.Value)
|
sel := nl.DeserializeTcU32Sel(datum.Value)
|
||||||
// only parse if we have a very basic redirect
|
u32.Sel = (*TcU32Sel)(unsafe.Pointer(sel))
|
||||||
if sel.Flags&nl.TC_U32_TERMINAL == 0 || sel.Nkeys != 1 {
|
if native != networkOrder {
|
||||||
return detailed, nil
|
// Handle the endianness of attributes
|
||||||
|
u32.Sel.Offmask = native.Uint16(htons(sel.Offmask))
|
||||||
|
u32.Sel.Hmask = native.Uint32(htonl(sel.Hmask))
|
||||||
|
for _, key := range u32.Sel.Keys {
|
||||||
|
key.Mask = native.Uint32(htonl(key.Mask))
|
||||||
|
key.Val = native.Uint32(htonl(key.Val))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case nl.TCA_U32_ACT:
|
case nl.TCA_U32_ACT:
|
||||||
tables, err := nl.ParseRouteAttr(datum.Value)
|
tables, err := nl.ParseRouteAttr(datum.Value)
|
||||||
@ -443,6 +472,8 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
|
|||||||
u32.RedirIndex = int(action.Ifindex)
|
u32.RedirIndex = int(action.Ifindex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case nl.TCA_U32_CLASSID:
|
||||||
|
u32.ClassId = native.Uint32(datum.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return detailed, nil
|
return detailed, nil
|
||||||
|
644
vendor/github.com/vishvananda/netlink/filter_test.go
generated
vendored
Normal file
644
vendor/github.com/vishvananda/netlink/filter_test.go
generated
vendored
Normal file
@ -0,0 +1,644 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFilterAddDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
redir, err := LinkByName("bar")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(redir); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdisc := &Ingress{
|
||||||
|
QdiscAttrs: QdiscAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Handle: MakeHandle(0xffff, 0),
|
||||||
|
Parent: HANDLE_INGRESS,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := QdiscAdd(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err := QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
_, ok := qdiscs[0].(*Ingress)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
classId := MakeHandle(1, 1)
|
||||||
|
filter := &U32{
|
||||||
|
FilterAttrs: FilterAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Parent: MakeHandle(0xffff, 0),
|
||||||
|
Priority: 1,
|
||||||
|
Protocol: syscall.ETH_P_IP,
|
||||||
|
},
|
||||||
|
RedirIndex: redir.Attrs().Index,
|
||||||
|
ClassId: classId,
|
||||||
|
}
|
||||||
|
if err := FilterAdd(filter); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
filters, err := FilterList(link, MakeHandle(0xffff, 0))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(filters) != 1 {
|
||||||
|
t.Fatal("Failed to add filter")
|
||||||
|
}
|
||||||
|
u32, ok := filters[0].(*U32)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Filter is the wrong type")
|
||||||
|
}
|
||||||
|
if u32.ClassId != classId {
|
||||||
|
t.Fatalf("ClassId of the filter is the wrong value")
|
||||||
|
}
|
||||||
|
if err := FilterDel(filter); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
filters, err = FilterList(link, MakeHandle(0xffff, 0))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(filters) != 0 {
|
||||||
|
t.Fatal("Failed to remove filter")
|
||||||
|
}
|
||||||
|
if err := QdiscDel(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 0 {
|
||||||
|
t.Fatal("Failed to remove qdisc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAdvancedFilterAddDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "baz"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("baz")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
index := link.Attrs().Index
|
||||||
|
|
||||||
|
qdiscHandle := MakeHandle(0x1, 0x0)
|
||||||
|
qdiscAttrs := QdiscAttrs{
|
||||||
|
LinkIndex: index,
|
||||||
|
Handle: qdiscHandle,
|
||||||
|
Parent: HANDLE_ROOT,
|
||||||
|
}
|
||||||
|
|
||||||
|
qdisc := NewHtb(qdiscAttrs)
|
||||||
|
if err := QdiscAdd(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err := QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
_, ok := qdiscs[0].(*Htb)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
classId := MakeHandle(0x1, 0x46cb)
|
||||||
|
classAttrs := ClassAttrs{
|
||||||
|
LinkIndex: index,
|
||||||
|
Parent: qdiscHandle,
|
||||||
|
Handle: classId,
|
||||||
|
}
|
||||||
|
htbClassAttrs := HtbClassAttrs{
|
||||||
|
Rate: 512 * 1024,
|
||||||
|
Buffer: 32 * 1024,
|
||||||
|
}
|
||||||
|
htbClass := NewHtbClass(classAttrs, htbClassAttrs)
|
||||||
|
if err = ClassReplace(htbClass); err != nil {
|
||||||
|
t.Fatalf("Failed to add a HTB class: %v", err)
|
||||||
|
}
|
||||||
|
classes, err := ClassList(link, qdiscHandle)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(classes) != 1 {
|
||||||
|
t.Fatal("Failed to add class")
|
||||||
|
}
|
||||||
|
_, ok = classes[0].(*HtbClass)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Class is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
u32SelKeys := []TcU32Key{
|
||||||
|
TcU32Key{
|
||||||
|
Mask: 0xff,
|
||||||
|
Val: 80,
|
||||||
|
Off: 20,
|
||||||
|
OffMask: 0,
|
||||||
|
},
|
||||||
|
TcU32Key{
|
||||||
|
Mask: 0xffff,
|
||||||
|
Val: 0x146ca,
|
||||||
|
Off: 32,
|
||||||
|
OffMask: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
filter := &U32{
|
||||||
|
FilterAttrs: FilterAttrs{
|
||||||
|
LinkIndex: index,
|
||||||
|
Parent: qdiscHandle,
|
||||||
|
Priority: 1,
|
||||||
|
Protocol: syscall.ETH_P_ALL,
|
||||||
|
},
|
||||||
|
Sel: &TcU32Sel{
|
||||||
|
Keys: u32SelKeys,
|
||||||
|
Flags: TC_U32_TERMINAL,
|
||||||
|
},
|
||||||
|
ClassId: classId,
|
||||||
|
Actions: []Action{},
|
||||||
|
}
|
||||||
|
if err := FilterAdd(filter); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
filters, err := FilterList(link, qdiscHandle)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(filters) != 1 {
|
||||||
|
t.Fatal("Failed to add filter")
|
||||||
|
}
|
||||||
|
|
||||||
|
u32, ok := filters[0].(*U32)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Filter is the wrong type")
|
||||||
|
}
|
||||||
|
// Endianness checks
|
||||||
|
if u32.Sel.Offmask != filter.Sel.Offmask {
|
||||||
|
t.Fatal("The endianness of TcU32Key.Sel.Offmask is wrong")
|
||||||
|
}
|
||||||
|
if u32.Sel.Hmask != filter.Sel.Hmask {
|
||||||
|
t.Fatal("The endianness of TcU32Key.Sel.Hmask is wrong")
|
||||||
|
}
|
||||||
|
for i, key := range u32.Sel.Keys {
|
||||||
|
if key.Mask != filter.Sel.Keys[i].Mask {
|
||||||
|
t.Fatal("The endianness of TcU32Key.Mask is wrong")
|
||||||
|
}
|
||||||
|
if key.Val != filter.Sel.Keys[i].Val {
|
||||||
|
t.Fatal("The endianness of TcU32Key.Val is wrong")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := FilterDel(filter); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
filters, err = FilterList(link, qdiscHandle)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(filters) != 0 {
|
||||||
|
t.Fatal("Failed to remove filter")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = ClassDel(htbClass); err != nil {
|
||||||
|
t.Fatalf("Failed to delete a HTP class: %v", err)
|
||||||
|
}
|
||||||
|
classes, err = ClassList(link, qdiscHandle)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(classes) != 0 {
|
||||||
|
t.Fatal("Failed to remove class")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := QdiscDel(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 0 {
|
||||||
|
t.Fatal("Failed to remove qdisc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterFwAddDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
redir, err := LinkByName("bar")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(redir); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
attrs := QdiscAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Handle: MakeHandle(0xffff, 0),
|
||||||
|
Parent: HANDLE_ROOT,
|
||||||
|
}
|
||||||
|
qdisc := NewHtb(attrs)
|
||||||
|
if err := QdiscAdd(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err := QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
_, ok := qdiscs[0].(*Htb)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
classattrs := ClassAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Parent: MakeHandle(0xffff, 0),
|
||||||
|
Handle: MakeHandle(0xffff, 2),
|
||||||
|
}
|
||||||
|
|
||||||
|
htbclassattrs := HtbClassAttrs{
|
||||||
|
Rate: 1234000,
|
||||||
|
Cbuffer: 1690,
|
||||||
|
}
|
||||||
|
class := NewHtbClass(classattrs, htbclassattrs)
|
||||||
|
if err := ClassAdd(class); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
classes, err := ClassList(link, MakeHandle(0xffff, 2))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(classes) != 1 {
|
||||||
|
t.Fatal("Failed to add class")
|
||||||
|
}
|
||||||
|
|
||||||
|
filterattrs := FilterAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Parent: MakeHandle(0xffff, 0),
|
||||||
|
Handle: MakeHandle(0, 0x6),
|
||||||
|
Priority: 1,
|
||||||
|
Protocol: syscall.ETH_P_IP,
|
||||||
|
}
|
||||||
|
fwattrs := FilterFwAttrs{
|
||||||
|
Buffer: 12345,
|
||||||
|
Rate: 1234,
|
||||||
|
PeakRate: 2345,
|
||||||
|
Action: TC_POLICE_SHOT,
|
||||||
|
ClassId: MakeHandle(0xffff, 2),
|
||||||
|
}
|
||||||
|
|
||||||
|
filter, err := NewFw(filterattrs, fwattrs)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := FilterAdd(filter); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
filters, err := FilterList(link, MakeHandle(0xffff, 0))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(filters) != 1 {
|
||||||
|
t.Fatal("Failed to add filter")
|
||||||
|
}
|
||||||
|
fw, ok := filters[0].(*Fw)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Filter is the wrong type")
|
||||||
|
}
|
||||||
|
if fw.Police.Rate.Rate != filter.Police.Rate.Rate {
|
||||||
|
t.Fatal("Police Rate doesn't match")
|
||||||
|
}
|
||||||
|
for i := range fw.Rtab {
|
||||||
|
if fw.Rtab[i] != filter.Rtab[i] {
|
||||||
|
t.Fatal("Rtab doesn't match")
|
||||||
|
}
|
||||||
|
if fw.Ptab[i] != filter.Ptab[i] {
|
||||||
|
t.Fatal("Ptab doesn't match")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fw.ClassId != filter.ClassId {
|
||||||
|
t.Fatal("ClassId doesn't match")
|
||||||
|
}
|
||||||
|
if fw.InDev != filter.InDev {
|
||||||
|
t.Fatal("InDev doesn't match")
|
||||||
|
}
|
||||||
|
if fw.AvRate != filter.AvRate {
|
||||||
|
t.Fatal("AvRate doesn't match")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := FilterDel(filter); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
filters, err = FilterList(link, MakeHandle(0xffff, 0))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(filters) != 0 {
|
||||||
|
t.Fatal("Failed to remove filter")
|
||||||
|
}
|
||||||
|
if err := ClassDel(class); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
classes, err = ClassList(link, MakeHandle(0xffff, 0))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(classes) != 0 {
|
||||||
|
t.Fatal("Failed to remove class")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := QdiscDel(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 0 {
|
||||||
|
t.Fatal("Failed to remove qdisc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterU32BpfAddDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
redir, err := LinkByName("bar")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(redir); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdisc := &Ingress{
|
||||||
|
QdiscAttrs: QdiscAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Handle: MakeHandle(0xffff, 0),
|
||||||
|
Parent: HANDLE_INGRESS,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := QdiscAdd(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err := QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
_, ok := qdiscs[0].(*Ingress)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_ACT, 1)
|
||||||
|
if err != nil {
|
||||||
|
t.Skipf("Loading bpf program failed: %s", err)
|
||||||
|
}
|
||||||
|
classId := MakeHandle(1, 1)
|
||||||
|
filter := &U32{
|
||||||
|
FilterAttrs: FilterAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Parent: MakeHandle(0xffff, 0),
|
||||||
|
Priority: 1,
|
||||||
|
Protocol: syscall.ETH_P_ALL,
|
||||||
|
},
|
||||||
|
ClassId: classId,
|
||||||
|
Actions: []Action{
|
||||||
|
&BpfAction{Fd: fd, Name: "simple"},
|
||||||
|
&MirredAction{
|
||||||
|
ActionAttrs: ActionAttrs{
|
||||||
|
Action: TC_ACT_STOLEN,
|
||||||
|
},
|
||||||
|
MirredAction: TCA_EGRESS_REDIR,
|
||||||
|
Ifindex: redir.Attrs().Index,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := FilterAdd(filter); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
filters, err := FilterList(link, MakeHandle(0xffff, 0))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(filters) != 1 {
|
||||||
|
t.Fatal("Failed to add filter")
|
||||||
|
}
|
||||||
|
u32, ok := filters[0].(*U32)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Filter is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(u32.Actions) != 2 {
|
||||||
|
t.Fatalf("Too few Actions in filter")
|
||||||
|
}
|
||||||
|
if u32.ClassId != classId {
|
||||||
|
t.Fatalf("ClassId of the filter is the wrong value")
|
||||||
|
}
|
||||||
|
bpfAction, ok := u32.Actions[0].(*BpfAction)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Action[0] is the wrong type")
|
||||||
|
}
|
||||||
|
if bpfAction.Fd != fd {
|
||||||
|
t.Fatal("Action Fd does not match")
|
||||||
|
}
|
||||||
|
if _, ok := u32.Actions[1].(*MirredAction); !ok {
|
||||||
|
t.Fatal("Action[1] is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := FilterDel(filter); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
filters, err = FilterList(link, MakeHandle(0xffff, 0))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(filters) != 0 {
|
||||||
|
t.Fatal("Failed to remove filter")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := QdiscDel(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 0 {
|
||||||
|
t.Fatal("Failed to remove qdisc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterClsActBpfAddDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
attrs := QdiscAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Handle: MakeHandle(0xffff, 0),
|
||||||
|
Parent: HANDLE_CLSACT,
|
||||||
|
}
|
||||||
|
qdisc := &GenericQdisc{
|
||||||
|
QdiscAttrs: attrs,
|
||||||
|
QdiscType: "clsact",
|
||||||
|
}
|
||||||
|
// This feature was added in kernel 4.5
|
||||||
|
if err := QdiscAdd(qdisc); err != nil {
|
||||||
|
t.Skipf("Failed adding clsact qdisc, unsupported kernel")
|
||||||
|
}
|
||||||
|
qdiscs, err := QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
if q, ok := qdiscs[0].(*GenericQdisc); !ok || q.Type() != "clsact" {
|
||||||
|
t.Fatal("qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
filterattrs := FilterAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Parent: HANDLE_MIN_EGRESS,
|
||||||
|
Handle: MakeHandle(0, 1),
|
||||||
|
Protocol: syscall.ETH_P_ALL,
|
||||||
|
Priority: 1,
|
||||||
|
}
|
||||||
|
fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_CLS, 1)
|
||||||
|
if err != nil {
|
||||||
|
t.Skipf("Loading bpf program failed: %s", err)
|
||||||
|
}
|
||||||
|
filter := &BpfFilter{
|
||||||
|
FilterAttrs: filterattrs,
|
||||||
|
Fd: fd,
|
||||||
|
Name: "simple",
|
||||||
|
DirectAction: true,
|
||||||
|
}
|
||||||
|
if filter.Fd < 0 {
|
||||||
|
t.Skipf("Failed to load bpf program")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := FilterAdd(filter); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
filters, err := FilterList(link, HANDLE_MIN_EGRESS)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(filters) != 1 {
|
||||||
|
t.Fatal("Failed to add filter")
|
||||||
|
}
|
||||||
|
bpf, ok := filters[0].(*BpfFilter)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Filter is the wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
if bpf.Fd != filter.Fd {
|
||||||
|
t.Fatal("Filter Fd does not match")
|
||||||
|
}
|
||||||
|
if bpf.DirectAction != filter.DirectAction {
|
||||||
|
t.Fatal("Filter DirectAction does not match")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := FilterDel(filter); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
filters, err = FilterList(link, HANDLE_MIN_EGRESS)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(filters) != 0 {
|
||||||
|
t.Fatal("Failed to remove filter")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := QdiscDel(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 0 {
|
||||||
|
t.Fatal("Failed to remove qdisc")
|
||||||
|
}
|
||||||
|
}
|
343
vendor/github.com/vishvananda/netlink/handle_test.go
generated
vendored
Normal file
343
vendor/github.com/vishvananda/netlink/handle_test.go
generated
vendored
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/vishvananda/netlink/nl"
|
||||||
|
"github.com/vishvananda/netns"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHandleCreateDelete(t *testing.T) {
|
||||||
|
h, err := NewHandle()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, f := range nl.SupportedNlFamilies {
|
||||||
|
sh, ok := h.sockets[f]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Handle socket(s) for family %d was not created", f)
|
||||||
|
}
|
||||||
|
if sh.Socket == nil {
|
||||||
|
t.Fatalf("Socket for family %d was not created", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Delete()
|
||||||
|
if h.sockets != nil {
|
||||||
|
t.Fatalf("Handle socket(s) were not destroyed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleCreateNetns(t *testing.T) {
|
||||||
|
skipUnlessRoot(t)
|
||||||
|
|
||||||
|
id := make([]byte, 4)
|
||||||
|
if _, err := io.ReadFull(rand.Reader, id); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ifName := "dummy-" + hex.EncodeToString(id)
|
||||||
|
|
||||||
|
// Create an handle on the current netns
|
||||||
|
curNs, err := netns.Get()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer curNs.Close()
|
||||||
|
|
||||||
|
ch, err := NewHandleAt(curNs)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer ch.Delete()
|
||||||
|
|
||||||
|
// Create an handle on a custom netns
|
||||||
|
newNs, err := netns.New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer newNs.Close()
|
||||||
|
|
||||||
|
nh, err := NewHandleAt(newNs)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer nh.Delete()
|
||||||
|
|
||||||
|
// Create an interface using the current handle
|
||||||
|
err = ch.LinkAdd(&Dummy{LinkAttrs{Name: ifName}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
l, err := ch.LinkByName(ifName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if l.Type() != "dummy" {
|
||||||
|
t.Fatalf("Unexpected link type: %s", l.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the new handle cannot find the interface
|
||||||
|
ll, err := nh.LinkByName(ifName)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Unexpected link found on netns %s: %v", newNs, ll)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the interface to the new netns
|
||||||
|
err = ch.LinkSetNsFd(l, int(newNs))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify new netns handle can find the interface while current cannot
|
||||||
|
ll, err = nh.LinkByName(ifName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if ll.Type() != "dummy" {
|
||||||
|
t.Fatalf("Unexpected link type: %s", ll.Type())
|
||||||
|
}
|
||||||
|
ll, err = ch.LinkByName(ifName)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Unexpected link found on netns %s: %v", curNs, ll)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleTimeout(t *testing.T) {
|
||||||
|
h, err := NewHandle()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer h.Delete()
|
||||||
|
|
||||||
|
for _, sh := range h.sockets {
|
||||||
|
verifySockTimeVal(t, sh.Socket.GetFd(), syscall.Timeval{Sec: 0, Usec: 0})
|
||||||
|
}
|
||||||
|
|
||||||
|
h.SetSocketTimeout(2*time.Second + 8*time.Millisecond)
|
||||||
|
|
||||||
|
for _, sh := range h.sockets {
|
||||||
|
verifySockTimeVal(t, sh.Socket.GetFd(), syscall.Timeval{Sec: 2, Usec: 8000})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifySockTimeVal(t *testing.T, fd int, tv syscall.Timeval) {
|
||||||
|
var (
|
||||||
|
tr syscall.Timeval
|
||||||
|
v = uint32(0x10)
|
||||||
|
)
|
||||||
|
_, _, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, uintptr(unsafe.Pointer(&tr)), uintptr(unsafe.Pointer(&v)), 0)
|
||||||
|
if errno != 0 {
|
||||||
|
t.Fatal(errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tr.Sec != tv.Sec || tr.Usec != tv.Usec {
|
||||||
|
t.Fatalf("Unexpected timeout value read: %v. Expected: %v", tr, tv)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, errno = syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, uintptr(unsafe.Pointer(&tr)), uintptr(unsafe.Pointer(&v)), 0)
|
||||||
|
if errno != 0 {
|
||||||
|
t.Fatal(errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tr.Sec != tv.Sec || tr.Usec != tv.Usec {
|
||||||
|
t.Fatalf("Unexpected timeout value read: %v. Expected: %v", tr, tv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
iter = 10
|
||||||
|
numThread = uint32(4)
|
||||||
|
prefix = "iface"
|
||||||
|
handle1 *Handle
|
||||||
|
handle2 *Handle
|
||||||
|
ns1 netns.NsHandle
|
||||||
|
ns2 netns.NsHandle
|
||||||
|
done uint32
|
||||||
|
initError error
|
||||||
|
once sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
func getXfrmState(thread int) *XfrmState {
|
||||||
|
return &XfrmState{
|
||||||
|
Src: net.IPv4(byte(192), byte(168), 1, byte(1+thread)),
|
||||||
|
Dst: net.IPv4(byte(192), byte(168), 2, byte(1+thread)),
|
||||||
|
Proto: XFRM_PROTO_AH,
|
||||||
|
Mode: XFRM_MODE_TUNNEL,
|
||||||
|
Spi: thread,
|
||||||
|
Auth: &XfrmStateAlgo{
|
||||||
|
Name: "hmac(sha256)",
|
||||||
|
Key: []byte("abcdefghijklmnopqrstuvwzyzABCDEF"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getXfrmPolicy(thread int) *XfrmPolicy {
|
||||||
|
return &XfrmPolicy{
|
||||||
|
Src: &net.IPNet{IP: net.IPv4(byte(10), byte(10), byte(thread), 0), Mask: []byte{255, 255, 255, 0}},
|
||||||
|
Dst: &net.IPNet{IP: net.IPv4(byte(10), byte(10), byte(thread), 0), Mask: []byte{255, 255, 255, 0}},
|
||||||
|
Proto: 17,
|
||||||
|
DstPort: 1234,
|
||||||
|
SrcPort: 5678,
|
||||||
|
Dir: XFRM_DIR_OUT,
|
||||||
|
Tmpls: []XfrmPolicyTmpl{
|
||||||
|
{
|
||||||
|
Src: net.IPv4(byte(192), byte(168), 1, byte(thread)),
|
||||||
|
Dst: net.IPv4(byte(192), byte(168), 2, byte(thread)),
|
||||||
|
Proto: XFRM_PROTO_ESP,
|
||||||
|
Mode: XFRM_MODE_TUNNEL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func initParallel() {
|
||||||
|
ns1, initError = netns.New()
|
||||||
|
if initError != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handle1, initError = NewHandleAt(ns1)
|
||||||
|
if initError != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ns2, initError = netns.New()
|
||||||
|
if initError != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handle2, initError = NewHandleAt(ns2)
|
||||||
|
if initError != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parallelDone() {
|
||||||
|
atomic.AddUint32(&done, 1)
|
||||||
|
if done == numThread {
|
||||||
|
if ns1.IsOpen() {
|
||||||
|
ns1.Close()
|
||||||
|
}
|
||||||
|
if ns2.IsOpen() {
|
||||||
|
ns2.Close()
|
||||||
|
}
|
||||||
|
if handle1 != nil {
|
||||||
|
handle1.Delete()
|
||||||
|
}
|
||||||
|
if handle2 != nil {
|
||||||
|
handle2.Delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do few route and xfrm operation on the two handles in parallel
|
||||||
|
func runParallelTests(t *testing.T, thread int) {
|
||||||
|
skipUnlessRoot(t)
|
||||||
|
defer parallelDone()
|
||||||
|
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
once.Do(initParallel)
|
||||||
|
if initError != nil {
|
||||||
|
t.Fatal(initError)
|
||||||
|
}
|
||||||
|
|
||||||
|
state := getXfrmState(thread)
|
||||||
|
policy := getXfrmPolicy(thread)
|
||||||
|
for i := 0; i < iter; i++ {
|
||||||
|
ifName := fmt.Sprintf("%s_%d_%d", prefix, thread, i)
|
||||||
|
link := &Dummy{LinkAttrs{Name: ifName}}
|
||||||
|
err := handle1.LinkAdd(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
l, err := handle1.LinkByName(ifName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = handle1.LinkSetUp(l)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
handle1.LinkSetNsFd(l, int(ns2))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = handle1.XfrmStateAdd(state)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = handle1.XfrmPolicyAdd(policy)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = handle2.LinkSetDown(l)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = handle2.XfrmStateAdd(state)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = handle2.XfrmPolicyAdd(policy)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = handle2.LinkByName(ifName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
handle2.LinkSetNsFd(l, int(ns1))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = handle1.LinkSetUp(l)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
l, err = handle1.LinkByName(ifName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = handle1.XfrmPolicyDel(policy)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = handle2.XfrmPolicyDel(policy)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = handle1.XfrmStateDel(state)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = handle2.XfrmStateDel(state)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleParallel1(t *testing.T) {
|
||||||
|
runParallelTests(t, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleParallel2(t *testing.T) {
|
||||||
|
runParallelTests(t, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleParallel3(t *testing.T) {
|
||||||
|
runParallelTests(t, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleParallel4(t *testing.T) {
|
||||||
|
runParallelTests(t, 4)
|
||||||
|
}
|
60
vendor/github.com/vishvananda/netlink/link_linux.go
generated
vendored
60
vendor/github.com/vishvananda/netlink/link_linux.go
generated
vendored
@ -58,6 +58,44 @@ func (h *Handle) ensureIndex(link *LinkAttrs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handle) LinkSetARPOff(link Link) error {
|
||||||
|
base := link.Attrs()
|
||||||
|
h.ensureIndex(base)
|
||||||
|
req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||||
|
|
||||||
|
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||||
|
msg.Change |= syscall.IFF_NOARP
|
||||||
|
msg.Flags |= syscall.IFF_NOARP
|
||||||
|
msg.Index = int32(base.Index)
|
||||||
|
req.AddData(msg)
|
||||||
|
|
||||||
|
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func LinkSetARPOff(link Link) error {
|
||||||
|
return pkgHandle.LinkSetARPOff(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) LinkSetARPOn(link Link) error {
|
||||||
|
base := link.Attrs()
|
||||||
|
h.ensureIndex(base)
|
||||||
|
req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||||
|
|
||||||
|
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||||
|
msg.Change |= syscall.IFF_NOARP
|
||||||
|
msg.Flags &= ^uint32(syscall.IFF_NOARP)
|
||||||
|
msg.Index = int32(base.Index)
|
||||||
|
req.AddData(msg)
|
||||||
|
|
||||||
|
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func LinkSetARPOn(link Link) error {
|
||||||
|
return pkgHandle.LinkSetARPOn(link)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handle) SetPromiscOn(link Link) error {
|
func (h *Handle) SetPromiscOn(link Link) error {
|
||||||
base := link.Attrs()
|
base := link.Attrs()
|
||||||
h.ensureIndex(base)
|
h.ensureIndex(base)
|
||||||
@ -65,7 +103,7 @@ func (h *Handle) SetPromiscOn(link Link) error {
|
|||||||
|
|
||||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||||
msg.Change = syscall.IFF_PROMISC
|
msg.Change = syscall.IFF_PROMISC
|
||||||
msg.Flags = syscall.IFF_UP
|
msg.Flags = syscall.IFF_PROMISC
|
||||||
msg.Index = int32(base.Index)
|
msg.Index = int32(base.Index)
|
||||||
req.AddData(msg)
|
req.AddData(msg)
|
||||||
|
|
||||||
@ -84,7 +122,7 @@ func (h *Handle) SetPromiscOff(link Link) error {
|
|||||||
|
|
||||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||||
msg.Change = syscall.IFF_PROMISC
|
msg.Change = syscall.IFF_PROMISC
|
||||||
msg.Flags = 0 & ^syscall.IFF_UP
|
msg.Flags = 0 & ^syscall.IFF_PROMISC
|
||||||
msg.Index = int32(base.Index)
|
msg.Index = int32(base.Index)
|
||||||
req.AddData(msg)
|
req.AddData(msg)
|
||||||
|
|
||||||
@ -1250,6 +1288,22 @@ func (h *Handle) LinkSetFlood(link Link, mode bool) error {
|
|||||||
return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_UNICAST_FLOOD)
|
return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_UNICAST_FLOOD)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LinkSetBrProxyArp(link Link, mode bool) error {
|
||||||
|
return pkgHandle.LinkSetBrProxyArp(link, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) LinkSetBrProxyArp(link Link, mode bool) error {
|
||||||
|
return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROXYARP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LinkSetBrProxyArpWiFi(link Link, mode bool) error {
|
||||||
|
return pkgHandle.LinkSetBrProxyArpWiFi(link, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handle) LinkSetBrProxyArpWiFi(link Link, mode bool) error {
|
||||||
|
return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROXYARP_WIFI)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
|
func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
|
||||||
base := link.Attrs()
|
base := link.Attrs()
|
||||||
h.ensureIndex(base)
|
h.ensureIndex(base)
|
||||||
@ -1332,7 +1386,7 @@ func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseBondData(link Link, data []syscall.NetlinkRouteAttr) {
|
func parseBondData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||||
bond := NewLinkBond(NewLinkAttrs())
|
bond := link.(*Bond)
|
||||||
for i := range data {
|
for i := range data {
|
||||||
switch data[i].Attr.Type {
|
switch data[i].Attr.Type {
|
||||||
case nl.IFLA_BOND_MODE:
|
case nl.IFLA_BOND_MODE:
|
||||||
|
1119
vendor/github.com/vishvananda/netlink/link_test.go
generated
vendored
Normal file
1119
vendor/github.com/vishvananda/netlink/link_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
194
vendor/github.com/vishvananda/netlink/neigh_test.go
generated
vendored
Normal file
194
vendor/github.com/vishvananda/netlink/neigh_test.go
generated
vendored
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type arpEntry struct {
|
||||||
|
ip net.IP
|
||||||
|
mac net.HardwareAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
type proxyEntry struct {
|
||||||
|
ip net.IP
|
||||||
|
dev int
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseMAC(s string) net.HardwareAddr {
|
||||||
|
m, err := net.ParseMAC(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func dumpContains(dump []Neigh, e arpEntry) bool {
|
||||||
|
for _, n := range dump {
|
||||||
|
if n.IP.Equal(e.ip) && (n.State&NUD_INCOMPLETE) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func dumpContainsProxy(dump []Neigh, p proxyEntry) bool {
|
||||||
|
for _, n := range dump {
|
||||||
|
if n.IP.Equal(p.ip) && (n.LinkIndex == p.dev) && (n.Flags&NTF_PROXY) == NTF_PROXY {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNeighAddDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
dummy := Dummy{LinkAttrs{Name: "neigh0"}}
|
||||||
|
if err := LinkAdd(&dummy); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureIndex(dummy.Attrs())
|
||||||
|
|
||||||
|
arpTable := []arpEntry{
|
||||||
|
{net.ParseIP("10.99.0.1"), parseMAC("aa:bb:cc:dd:00:01")},
|
||||||
|
{net.ParseIP("10.99.0.2"), parseMAC("aa:bb:cc:dd:00:02")},
|
||||||
|
{net.ParseIP("10.99.0.3"), parseMAC("aa:bb:cc:dd:00:03")},
|
||||||
|
{net.ParseIP("10.99.0.4"), parseMAC("aa:bb:cc:dd:00:04")},
|
||||||
|
{net.ParseIP("10.99.0.5"), parseMAC("aa:bb:cc:dd:00:05")},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the arpTable
|
||||||
|
for _, entry := range arpTable {
|
||||||
|
err := NeighAdd(&Neigh{
|
||||||
|
LinkIndex: dummy.Index,
|
||||||
|
State: NUD_REACHABLE,
|
||||||
|
IP: entry.ip,
|
||||||
|
HardwareAddr: entry.mac,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to NeighAdd: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump and see that all added entries are there
|
||||||
|
dump, err := NeighList(dummy.Index, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to NeighList: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range arpTable {
|
||||||
|
if !dumpContains(dump, entry) {
|
||||||
|
t.Errorf("Dump does not contain: %v", entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the arpTable
|
||||||
|
for _, entry := range arpTable {
|
||||||
|
err := NeighDel(&Neigh{
|
||||||
|
LinkIndex: dummy.Index,
|
||||||
|
IP: entry.ip,
|
||||||
|
HardwareAddr: entry.mac,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to NeighDel: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: seems not working because of cache
|
||||||
|
//// Dump and see that none of deleted entries are there
|
||||||
|
//dump, err = NeighList(dummy.Index, 0)
|
||||||
|
//if err != nil {
|
||||||
|
//t.Errorf("Failed to NeighList: %v", err)
|
||||||
|
//}
|
||||||
|
|
||||||
|
//for _, entry := range arpTable {
|
||||||
|
//if dumpContains(dump, entry) {
|
||||||
|
//t.Errorf("Dump contains: %v", entry)
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
|
||||||
|
if err := LinkDel(&dummy); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNeighAddDelProxy(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
dummy := Dummy{LinkAttrs{Name: "neigh0"}}
|
||||||
|
if err := LinkAdd(&dummy); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureIndex(dummy.Attrs())
|
||||||
|
|
||||||
|
proxyTable := []proxyEntry{
|
||||||
|
{net.ParseIP("10.99.0.1"), dummy.Index},
|
||||||
|
{net.ParseIP("10.99.0.2"), dummy.Index},
|
||||||
|
{net.ParseIP("10.99.0.3"), dummy.Index},
|
||||||
|
{net.ParseIP("10.99.0.4"), dummy.Index},
|
||||||
|
{net.ParseIP("10.99.0.5"), dummy.Index},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the proxyTable
|
||||||
|
for _, entry := range proxyTable {
|
||||||
|
err := NeighAdd(&Neigh{
|
||||||
|
LinkIndex: dummy.Index,
|
||||||
|
Flags: NTF_PROXY,
|
||||||
|
IP: entry.ip,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to NeighAdd: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump and see that all added entries are there
|
||||||
|
dump, err := NeighProxyList(dummy.Index, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to NeighList: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range proxyTable {
|
||||||
|
if !dumpContainsProxy(dump, entry) {
|
||||||
|
t.Errorf("Dump does not contain: %v", entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the proxyTable
|
||||||
|
for _, entry := range proxyTable {
|
||||||
|
err := NeighDel(&Neigh{
|
||||||
|
LinkIndex: dummy.Index,
|
||||||
|
Flags: NTF_PROXY,
|
||||||
|
IP: entry.ip,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to NeighDel: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump and see that none of deleted entries are there
|
||||||
|
dump, err = NeighProxyList(dummy.Index, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to NeighList: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range proxyTable {
|
||||||
|
if dumpContainsProxy(dump, entry) {
|
||||||
|
t.Errorf("Dump contains: %v", entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := LinkDel(&dummy); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
58
vendor/github.com/vishvananda/netlink/netlink_test.go
generated
vendored
Normal file
58
vendor/github.com/vishvananda/netlink/netlink_test.go
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/vishvananda/netns"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tearDownNetlinkTest func()
|
||||||
|
|
||||||
|
func skipUnlessRoot(t *testing.T) {
|
||||||
|
if os.Getuid() != 0 {
|
||||||
|
msg := "Skipped test because it requires root privileges."
|
||||||
|
log.Printf(msg)
|
||||||
|
t.Skip(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUpNetlinkTest(t *testing.T) tearDownNetlinkTest {
|
||||||
|
skipUnlessRoot(t)
|
||||||
|
|
||||||
|
// new temporary namespace so we don't pollute the host
|
||||||
|
// lock thread since the namespace is thread local
|
||||||
|
runtime.LockOSThread()
|
||||||
|
var err error
|
||||||
|
ns, err := netns.New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Failed to create newns", ns)
|
||||||
|
}
|
||||||
|
|
||||||
|
return func() {
|
||||||
|
ns.Close()
|
||||||
|
runtime.UnlockOSThread()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUpMPLSNetlinkTest(t *testing.T) tearDownNetlinkTest {
|
||||||
|
if _, err := os.Stat("/proc/sys/net/mpls/platform_labels"); err != nil {
|
||||||
|
msg := "Skipped test because it requires MPLS support."
|
||||||
|
log.Printf(msg)
|
||||||
|
t.Skip(msg)
|
||||||
|
}
|
||||||
|
f := setUpNetlinkTest(t)
|
||||||
|
setUpF := func(path, value string) {
|
||||||
|
file, err := os.Create(path)
|
||||||
|
defer file.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to open %s: %s", path, err)
|
||||||
|
}
|
||||||
|
file.WriteString(value)
|
||||||
|
}
|
||||||
|
setUpF("/proc/sys/net/mpls/platform_labels", "1024")
|
||||||
|
setUpF("/proc/sys/net/mpls/conf/lo/input", "1")
|
||||||
|
return f
|
||||||
|
}
|
10
vendor/github.com/vishvananda/netlink/netlink_unspecified.go
generated
vendored
10
vendor/github.com/vishvananda/netlink/netlink_unspecified.go
generated
vendored
@ -16,7 +16,7 @@ func LinkSetMTU(link Link, mtu int) error {
|
|||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func LinkSetMaster(link Link, master *Link) error {
|
func LinkSetMaster(link Link, master *Bridge) error {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +64,14 @@ func LinkSetXdpFd(link Link, fd int) error {
|
|||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LinkSetARPOff(link Link) error {
|
||||||
|
return ErrNotImplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
func LinkSetARPOn(link Link) error {
|
||||||
|
return ErrNotImplemented
|
||||||
|
}
|
||||||
|
|
||||||
func LinkByName(name string) (Link, error) {
|
func LinkByName(name string) (Link, error) {
|
||||||
return nil, ErrNotImplemented
|
return nil, ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
29
vendor/github.com/vishvananda/netlink/nl/addr_linux.go
generated
vendored
29
vendor/github.com/vishvananda/netlink/nl/addr_linux.go
generated
vendored
@ -45,3 +45,32 @@ func (msg *IfAddrmsg) Serialize() []byte {
|
|||||||
func (msg *IfAddrmsg) Len() int {
|
func (msg *IfAddrmsg) Len() int {
|
||||||
return syscall.SizeofIfAddrmsg
|
return syscall.SizeofIfAddrmsg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// struct ifa_cacheinfo {
|
||||||
|
// __u32 ifa_prefered;
|
||||||
|
// __u32 ifa_valid;
|
||||||
|
// __u32 cstamp; /* created timestamp, hundredths of seconds */
|
||||||
|
// __u32 tstamp; /* updated timestamp, hundredths of seconds */
|
||||||
|
// };
|
||||||
|
|
||||||
|
const IFA_CACHEINFO = 6
|
||||||
|
const SizeofIfaCacheInfo = 0x10
|
||||||
|
|
||||||
|
type IfaCacheInfo struct {
|
||||||
|
IfaPrefered uint32
|
||||||
|
IfaValid uint32
|
||||||
|
Cstamp uint32
|
||||||
|
Tstamp uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *IfaCacheInfo) Len() int {
|
||||||
|
return SizeofIfaCacheInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeserializeIfaCacheInfo(b []byte) *IfaCacheInfo {
|
||||||
|
return (*IfaCacheInfo)(unsafe.Pointer(&b[0:SizeofIfaCacheInfo][0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *IfaCacheInfo) Serialize() []byte {
|
||||||
|
return (*(*[SizeofIfaCacheInfo]byte)(unsafe.Pointer(msg)))[:]
|
||||||
|
}
|
||||||
|
68
vendor/github.com/vishvananda/netlink/nl/addr_linux_test.go
generated
vendored
Normal file
68
vendor/github.com/vishvananda/netlink/nl/addr_linux_test.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package nl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (msg *IfAddrmsg) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
b[0] = msg.Family
|
||||||
|
b[1] = msg.Prefixlen
|
||||||
|
b[2] = msg.Flags
|
||||||
|
b[3] = msg.Scope
|
||||||
|
native.PutUint32(b[4:8], msg.Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *IfAddrmsg) serializeSafe() []byte {
|
||||||
|
len := syscall.SizeofIfAddrmsg
|
||||||
|
b := make([]byte, len)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeIfAddrmsgSafe(b []byte) *IfAddrmsg {
|
||||||
|
var msg = IfAddrmsg{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:syscall.SizeofIfAddrmsg]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIfAddrmsgDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, syscall.SizeofIfAddrmsg)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeIfAddrmsgSafe(orig)
|
||||||
|
msg := DeserializeIfAddrmsg(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *IfaCacheInfo) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
native.PutUint32(b[0:4], uint32(msg.IfaPrefered))
|
||||||
|
native.PutUint32(b[4:8], uint32(msg.IfaValid))
|
||||||
|
native.PutUint32(b[8:12], uint32(msg.Cstamp))
|
||||||
|
native.PutUint32(b[12:16], uint32(msg.Tstamp))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *IfaCacheInfo) serializeSafe() []byte {
|
||||||
|
length := SizeofIfaCacheInfo
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeIfaCacheInfoSafe(b []byte) *IfaCacheInfo {
|
||||||
|
var msg = IfaCacheInfo{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofIfaCacheInfo]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIfaCacheInfoDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofIfaCacheInfo)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeIfaCacheInfoSafe(orig)
|
||||||
|
msg := DeserializeIfaCacheInfo(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
189
vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go
generated
vendored
Normal file
189
vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go
generated
vendored
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
package nl
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// Track the message sizes for the correct serialization/deserialization
|
||||||
|
const (
|
||||||
|
SizeofNfgenmsg = 4
|
||||||
|
SizeofNfattr = 4
|
||||||
|
SizeofNfConntrack = 376
|
||||||
|
SizeofNfctTupleHead = 52
|
||||||
|
)
|
||||||
|
|
||||||
|
var L4ProtoMap = map[uint8]string{
|
||||||
|
6: "tcp",
|
||||||
|
17: "udp",
|
||||||
|
}
|
||||||
|
|
||||||
|
// All the following constants are coming from:
|
||||||
|
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/netfilter/nfnetlink_conntrack.h
|
||||||
|
|
||||||
|
// enum cntl_msg_types {
|
||||||
|
// IPCTNL_MSG_CT_NEW,
|
||||||
|
// IPCTNL_MSG_CT_GET,
|
||||||
|
// IPCTNL_MSG_CT_DELETE,
|
||||||
|
// IPCTNL_MSG_CT_GET_CTRZERO,
|
||||||
|
// IPCTNL_MSG_CT_GET_STATS_CPU,
|
||||||
|
// IPCTNL_MSG_CT_GET_STATS,
|
||||||
|
// IPCTNL_MSG_CT_GET_DYING,
|
||||||
|
// IPCTNL_MSG_CT_GET_UNCONFIRMED,
|
||||||
|
//
|
||||||
|
// IPCTNL_MSG_MAX
|
||||||
|
// };
|
||||||
|
const (
|
||||||
|
IPCTNL_MSG_CT_GET = 1
|
||||||
|
IPCTNL_MSG_CT_DELETE = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// #define NFNETLINK_V0 0
|
||||||
|
const (
|
||||||
|
NFNETLINK_V0 = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// #define NLA_F_NESTED (1 << 15)
|
||||||
|
const (
|
||||||
|
NLA_F_NESTED = (1 << 15)
|
||||||
|
)
|
||||||
|
|
||||||
|
// enum ctattr_type {
|
||||||
|
// CTA_UNSPEC,
|
||||||
|
// CTA_TUPLE_ORIG,
|
||||||
|
// CTA_TUPLE_REPLY,
|
||||||
|
// CTA_STATUS,
|
||||||
|
// CTA_PROTOINFO,
|
||||||
|
// CTA_HELP,
|
||||||
|
// CTA_NAT_SRC,
|
||||||
|
// #define CTA_NAT CTA_NAT_SRC /* backwards compatibility */
|
||||||
|
// CTA_TIMEOUT,
|
||||||
|
// CTA_MARK,
|
||||||
|
// CTA_COUNTERS_ORIG,
|
||||||
|
// CTA_COUNTERS_REPLY,
|
||||||
|
// CTA_USE,
|
||||||
|
// CTA_ID,
|
||||||
|
// CTA_NAT_DST,
|
||||||
|
// CTA_TUPLE_MASTER,
|
||||||
|
// CTA_SEQ_ADJ_ORIG,
|
||||||
|
// CTA_NAT_SEQ_ADJ_ORIG = CTA_SEQ_ADJ_ORIG,
|
||||||
|
// CTA_SEQ_ADJ_REPLY,
|
||||||
|
// CTA_NAT_SEQ_ADJ_REPLY = CTA_SEQ_ADJ_REPLY,
|
||||||
|
// CTA_SECMARK, /* obsolete */
|
||||||
|
// CTA_ZONE,
|
||||||
|
// CTA_SECCTX,
|
||||||
|
// CTA_TIMESTAMP,
|
||||||
|
// CTA_MARK_MASK,
|
||||||
|
// CTA_LABELS,
|
||||||
|
// CTA_LABELS_MASK,
|
||||||
|
// __CTA_MAX
|
||||||
|
// };
|
||||||
|
const (
|
||||||
|
CTA_TUPLE_ORIG = 1
|
||||||
|
CTA_TUPLE_REPLY = 2
|
||||||
|
CTA_STATUS = 3
|
||||||
|
CTA_TIMEOUT = 8
|
||||||
|
CTA_MARK = 9
|
||||||
|
CTA_PROTOINFO = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
// enum ctattr_tuple {
|
||||||
|
// CTA_TUPLE_UNSPEC,
|
||||||
|
// CTA_TUPLE_IP,
|
||||||
|
// CTA_TUPLE_PROTO,
|
||||||
|
// CTA_TUPLE_ZONE,
|
||||||
|
// __CTA_TUPLE_MAX
|
||||||
|
// };
|
||||||
|
// #define CTA_TUPLE_MAX (__CTA_TUPLE_MAX - 1)
|
||||||
|
const (
|
||||||
|
CTA_TUPLE_IP = 1
|
||||||
|
CTA_TUPLE_PROTO = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// enum ctattr_ip {
|
||||||
|
// CTA_IP_UNSPEC,
|
||||||
|
// CTA_IP_V4_SRC,
|
||||||
|
// CTA_IP_V4_DST,
|
||||||
|
// CTA_IP_V6_SRC,
|
||||||
|
// CTA_IP_V6_DST,
|
||||||
|
// __CTA_IP_MAX
|
||||||
|
// };
|
||||||
|
// #define CTA_IP_MAX (__CTA_IP_MAX - 1)
|
||||||
|
const (
|
||||||
|
CTA_IP_V4_SRC = 1
|
||||||
|
CTA_IP_V4_DST = 2
|
||||||
|
CTA_IP_V6_SRC = 3
|
||||||
|
CTA_IP_V6_DST = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
// enum ctattr_l4proto {
|
||||||
|
// CTA_PROTO_UNSPEC,
|
||||||
|
// CTA_PROTO_NUM,
|
||||||
|
// CTA_PROTO_SRC_PORT,
|
||||||
|
// CTA_PROTO_DST_PORT,
|
||||||
|
// CTA_PROTO_ICMP_ID,
|
||||||
|
// CTA_PROTO_ICMP_TYPE,
|
||||||
|
// CTA_PROTO_ICMP_CODE,
|
||||||
|
// CTA_PROTO_ICMPV6_ID,
|
||||||
|
// CTA_PROTO_ICMPV6_TYPE,
|
||||||
|
// CTA_PROTO_ICMPV6_CODE,
|
||||||
|
// __CTA_PROTO_MAX
|
||||||
|
// };
|
||||||
|
// #define CTA_PROTO_MAX (__CTA_PROTO_MAX - 1)
|
||||||
|
const (
|
||||||
|
CTA_PROTO_NUM = 1
|
||||||
|
CTA_PROTO_SRC_PORT = 2
|
||||||
|
CTA_PROTO_DST_PORT = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
// enum ctattr_protoinfo {
|
||||||
|
// CTA_PROTOINFO_UNSPEC,
|
||||||
|
// CTA_PROTOINFO_TCP,
|
||||||
|
// CTA_PROTOINFO_DCCP,
|
||||||
|
// CTA_PROTOINFO_SCTP,
|
||||||
|
// __CTA_PROTOINFO_MAX
|
||||||
|
// };
|
||||||
|
// #define CTA_PROTOINFO_MAX (__CTA_PROTOINFO_MAX - 1)
|
||||||
|
const (
|
||||||
|
CTA_PROTOINFO_TCP = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// enum ctattr_protoinfo_tcp {
|
||||||
|
// CTA_PROTOINFO_TCP_UNSPEC,
|
||||||
|
// CTA_PROTOINFO_TCP_STATE,
|
||||||
|
// CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
|
||||||
|
// CTA_PROTOINFO_TCP_WSCALE_REPLY,
|
||||||
|
// CTA_PROTOINFO_TCP_FLAGS_ORIGINAL,
|
||||||
|
// CTA_PROTOINFO_TCP_FLAGS_REPLY,
|
||||||
|
// __CTA_PROTOINFO_TCP_MAX
|
||||||
|
// };
|
||||||
|
// #define CTA_PROTOINFO_TCP_MAX (__CTA_PROTOINFO_TCP_MAX - 1)
|
||||||
|
const (
|
||||||
|
CTA_PROTOINFO_TCP_STATE = 1
|
||||||
|
CTA_PROTOINFO_TCP_WSCALE_ORIGINAL = 2
|
||||||
|
CTA_PROTOINFO_TCP_WSCALE_REPLY = 3
|
||||||
|
CTA_PROTOINFO_TCP_FLAGS_ORIGINAL = 4
|
||||||
|
CTA_PROTOINFO_TCP_FLAGS_REPLY = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
// /* General form of address family dependent message.
|
||||||
|
// */
|
||||||
|
// struct nfgenmsg {
|
||||||
|
// __u8 nfgen_family; /* AF_xxx */
|
||||||
|
// __u8 version; /* nfnetlink version */
|
||||||
|
// __be16 res_id; /* resource id */
|
||||||
|
// };
|
||||||
|
type Nfgenmsg struct {
|
||||||
|
NfgenFamily uint8
|
||||||
|
Version uint8
|
||||||
|
ResId uint16 // big endian
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *Nfgenmsg) Len() int {
|
||||||
|
return SizeofNfgenmsg
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeserializeNfgenmsg(b []byte) *Nfgenmsg {
|
||||||
|
return (*Nfgenmsg)(unsafe.Pointer(&b[0:SizeofNfgenmsg][0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *Nfgenmsg) Serialize() []byte {
|
||||||
|
return (*(*[SizeofNfgenmsg]byte)(unsafe.Pointer(msg)))[:]
|
||||||
|
}
|
5
vendor/github.com/vishvananda/netlink/nl/link_linux.go
generated
vendored
5
vendor/github.com/vishvananda/netlink/nl/link_linux.go
generated
vendored
@ -102,7 +102,10 @@ const (
|
|||||||
IFLA_BRPORT_FAST_LEAVE
|
IFLA_BRPORT_FAST_LEAVE
|
||||||
IFLA_BRPORT_LEARNING
|
IFLA_BRPORT_LEARNING
|
||||||
IFLA_BRPORT_UNICAST_FLOOD
|
IFLA_BRPORT_UNICAST_FLOOD
|
||||||
IFLA_BRPORT_MAX = IFLA_BRPORT_UNICAST_FLOOD
|
IFLA_BRPORT_PROXYARP
|
||||||
|
IFLA_BRPORT_LEARNING_SYNC
|
||||||
|
IFLA_BRPORT_PROXYARP_WIFI
|
||||||
|
IFLA_BRPORT_MAX = IFLA_BRPORT_PROXYARP_WIFI
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
199
vendor/github.com/vishvananda/netlink/nl/link_linux_test.go
generated
vendored
Normal file
199
vendor/github.com/vishvananda/netlink/nl/link_linux_test.go
generated
vendored
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
package nl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (msg *VfMac) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
native.PutUint32(b[0:4], uint32(msg.Vf))
|
||||||
|
copy(b[4:36], msg.Mac[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *VfMac) serializeSafe() []byte {
|
||||||
|
length := SizeofVfMac
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeVfMacSafe(b []byte) *VfMac {
|
||||||
|
var msg = VfMac{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofVfMac]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVfMacDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofVfMac)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeVfMacSafe(orig)
|
||||||
|
msg := DeserializeVfMac(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *VfVlan) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
native.PutUint32(b[0:4], uint32(msg.Vf))
|
||||||
|
native.PutUint32(b[4:8], uint32(msg.Vlan))
|
||||||
|
native.PutUint32(b[8:12], uint32(msg.Qos))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *VfVlan) serializeSafe() []byte {
|
||||||
|
length := SizeofVfVlan
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeVfVlanSafe(b []byte) *VfVlan {
|
||||||
|
var msg = VfVlan{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofVfVlan]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVfVlanDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofVfVlan)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeVfVlanSafe(orig)
|
||||||
|
msg := DeserializeVfVlan(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *VfTxRate) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
native.PutUint32(b[0:4], uint32(msg.Vf))
|
||||||
|
native.PutUint32(b[4:8], uint32(msg.Rate))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *VfTxRate) serializeSafe() []byte {
|
||||||
|
length := SizeofVfTxRate
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeVfTxRateSafe(b []byte) *VfTxRate {
|
||||||
|
var msg = VfTxRate{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofVfTxRate]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVfTxRateDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofVfTxRate)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeVfTxRateSafe(orig)
|
||||||
|
msg := DeserializeVfTxRate(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *VfRate) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
native.PutUint32(b[0:4], uint32(msg.Vf))
|
||||||
|
native.PutUint32(b[4:8], uint32(msg.MinTxRate))
|
||||||
|
native.PutUint32(b[8:12], uint32(msg.MaxTxRate))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *VfRate) serializeSafe() []byte {
|
||||||
|
length := SizeofVfRate
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeVfRateSafe(b []byte) *VfRate {
|
||||||
|
var msg = VfRate{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofVfRate]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVfRateDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofVfRate)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeVfRateSafe(orig)
|
||||||
|
msg := DeserializeVfRate(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *VfSpoofchk) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
native.PutUint32(b[0:4], uint32(msg.Vf))
|
||||||
|
native.PutUint32(b[4:8], uint32(msg.Setting))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *VfSpoofchk) serializeSafe() []byte {
|
||||||
|
length := SizeofVfSpoofchk
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeVfSpoofchkSafe(b []byte) *VfSpoofchk {
|
||||||
|
var msg = VfSpoofchk{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofVfSpoofchk]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVfSpoofchkDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofVfSpoofchk)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeVfSpoofchkSafe(orig)
|
||||||
|
msg := DeserializeVfSpoofchk(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *VfLinkState) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
native.PutUint32(b[0:4], uint32(msg.Vf))
|
||||||
|
native.PutUint32(b[4:8], uint32(msg.LinkState))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *VfLinkState) serializeSafe() []byte {
|
||||||
|
length := SizeofVfLinkState
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeVfLinkStateSafe(b []byte) *VfLinkState {
|
||||||
|
var msg = VfLinkState{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofVfLinkState]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVfLinkStateDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofVfLinkState)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeVfLinkStateSafe(orig)
|
||||||
|
msg := DeserializeVfLinkState(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *VfRssQueryEn) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
native.PutUint32(b[0:4], uint32(msg.Vf))
|
||||||
|
native.PutUint32(b[4:8], uint32(msg.Setting))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *VfRssQueryEn) serializeSafe() []byte {
|
||||||
|
length := SizeofVfRssQueryEn
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeVfRssQueryEnSafe(b []byte) *VfRssQueryEn {
|
||||||
|
var msg = VfRssQueryEn{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofVfRssQueryEn]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVfRssQueryEnDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofVfRssQueryEn)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeVfRssQueryEnSafe(orig)
|
||||||
|
msg := DeserializeVfRssQueryEn(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
18
vendor/github.com/vishvananda/netlink/nl/nl_linux.go
generated
vendored
18
vendor/github.com/vishvananda/netlink/nl/nl_linux.go
generated
vendored
@ -24,7 +24,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// SupportedNlFamilies contains the list of netlink families this netlink package supports
|
// SupportedNlFamilies contains the list of netlink families this netlink package supports
|
||||||
var SupportedNlFamilies = []int{syscall.NETLINK_ROUTE, syscall.NETLINK_XFRM}
|
var SupportedNlFamilies = []int{syscall.NETLINK_ROUTE, syscall.NETLINK_XFRM, syscall.NETLINK_NETFILTER}
|
||||||
|
|
||||||
var nextSeqNr uint32
|
var nextSeqNr uint32
|
||||||
|
|
||||||
@ -321,6 +321,7 @@ func (a *RtAttr) Serialize() []byte {
|
|||||||
type NetlinkRequest struct {
|
type NetlinkRequest struct {
|
||||||
syscall.NlMsghdr
|
syscall.NlMsghdr
|
||||||
Data []NetlinkRequestData
|
Data []NetlinkRequestData
|
||||||
|
RawData []byte
|
||||||
Sockets map[int]*SocketHandle
|
Sockets map[int]*SocketHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,6 +333,8 @@ func (req *NetlinkRequest) Serialize() []byte {
|
|||||||
dataBytes[i] = data.Serialize()
|
dataBytes[i] = data.Serialize()
|
||||||
length = length + len(dataBytes[i])
|
length = length + len(dataBytes[i])
|
||||||
}
|
}
|
||||||
|
length += len(req.RawData)
|
||||||
|
|
||||||
req.Len = uint32(length)
|
req.Len = uint32(length)
|
||||||
b := make([]byte, length)
|
b := make([]byte, length)
|
||||||
hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:]
|
hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:]
|
||||||
@ -343,6 +346,10 @@ func (req *NetlinkRequest) Serialize() []byte {
|
|||||||
next = next + 1
|
next = next + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Add the raw data if any
|
||||||
|
if len(req.RawData) > 0 {
|
||||||
|
copy(b[next:length], req.RawData)
|
||||||
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,6 +359,13 @@ func (req *NetlinkRequest) AddData(data NetlinkRequestData) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddRawData adds raw bytes to the end of the NetlinkRequest object during serialization
|
||||||
|
func (req *NetlinkRequest) AddRawData(data []byte) {
|
||||||
|
if data != nil {
|
||||||
|
req.RawData = append(req.RawData, data...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Execute the request against a the given sockType.
|
// Execute the request against a the given sockType.
|
||||||
// Returns a list of netlink messages in serialized format, optionally filtered
|
// Returns a list of netlink messages in serialized format, optionally filtered
|
||||||
// by resType.
|
// by resType.
|
||||||
@ -451,7 +465,7 @@ type NetlinkSocket struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
|
func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
|
||||||
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol)
|
fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW|syscall.SOCK_CLOEXEC, protocol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
62
vendor/github.com/vishvananda/netlink/nl/nl_linux_test.go
generated
vendored
Normal file
62
vendor/github.com/vishvananda/netlink/nl/nl_linux_test.go
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package nl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"reflect"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testSerializer interface {
|
||||||
|
serializeSafe() []byte
|
||||||
|
Serialize() []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func testDeserializeSerialize(t *testing.T, orig []byte, safemsg testSerializer, msg testSerializer) {
|
||||||
|
if !reflect.DeepEqual(safemsg, msg) {
|
||||||
|
t.Fatal("Deserialization failed.\n", safemsg, "\n", msg)
|
||||||
|
}
|
||||||
|
safe := msg.serializeSafe()
|
||||||
|
if !bytes.Equal(safe, orig) {
|
||||||
|
t.Fatal("Safe serialization failed.\n", safe, "\n", orig)
|
||||||
|
}
|
||||||
|
b := msg.Serialize()
|
||||||
|
if !bytes.Equal(b, safe) {
|
||||||
|
t.Fatal("Serialization failed.\n", b, "\n", safe)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *IfInfomsg) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
b[0] = msg.Family
|
||||||
|
// pad byte is skipped because it is not exported on linux/s390x
|
||||||
|
native.PutUint16(b[2:4], msg.Type)
|
||||||
|
native.PutUint32(b[4:8], uint32(msg.Index))
|
||||||
|
native.PutUint32(b[8:12], msg.Flags)
|
||||||
|
native.PutUint32(b[12:16], msg.Change)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *IfInfomsg) serializeSafe() []byte {
|
||||||
|
length := syscall.SizeofIfInfomsg
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeIfInfomsgSafe(b []byte) *IfInfomsg {
|
||||||
|
var msg = IfInfomsg{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:syscall.SizeofIfInfomsg]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIfInfomsgDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, syscall.SizeofIfInfomsg)
|
||||||
|
rand.Read(orig)
|
||||||
|
// zero out the pad byte
|
||||||
|
orig[1] = 0
|
||||||
|
safemsg := deserializeIfInfomsgSafe(orig)
|
||||||
|
msg := DeserializeIfInfomsg(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
43
vendor/github.com/vishvananda/netlink/nl/route_linux_test.go
generated
vendored
Normal file
43
vendor/github.com/vishvananda/netlink/nl/route_linux_test.go
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package nl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (msg *RtMsg) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
b[0] = msg.Family
|
||||||
|
b[1] = msg.Dst_len
|
||||||
|
b[2] = msg.Src_len
|
||||||
|
b[3] = msg.Tos
|
||||||
|
b[4] = msg.Table
|
||||||
|
b[5] = msg.Protocol
|
||||||
|
b[6] = msg.Scope
|
||||||
|
b[7] = msg.Type
|
||||||
|
native.PutUint32(b[8:12], msg.Flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *RtMsg) serializeSafe() []byte {
|
||||||
|
len := syscall.SizeofRtMsg
|
||||||
|
b := make([]byte, len)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeRtMsgSafe(b []byte) *RtMsg {
|
||||||
|
var msg = RtMsg{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:syscall.SizeofRtMsg]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRtMsgDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, syscall.SizeofRtMsg)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeRtMsgSafe(orig)
|
||||||
|
msg := DeserializeRtMsg(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
173
vendor/github.com/vishvananda/netlink/nl/tc_linux_test.go
generated
vendored
Normal file
173
vendor/github.com/vishvananda/netlink/nl/tc_linux_test.go
generated
vendored
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
package nl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
/* TcMsg */
|
||||||
|
func (msg *TcMsg) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
b[0] = msg.Family
|
||||||
|
copy(b[1:4], msg.Pad[:])
|
||||||
|
native.PutUint32(b[4:8], uint32(msg.Ifindex))
|
||||||
|
native.PutUint32(b[8:12], msg.Handle)
|
||||||
|
native.PutUint32(b[12:16], msg.Parent)
|
||||||
|
native.PutUint32(b[16:20], msg.Info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *TcMsg) serializeSafe() []byte {
|
||||||
|
length := SizeofTcMsg
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeTcMsgSafe(b []byte) *TcMsg {
|
||||||
|
var msg = TcMsg{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofTcMsg]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTcMsgDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofTcMsg)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeTcMsgSafe(orig)
|
||||||
|
msg := DeserializeTcMsg(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TcActionMsg */
|
||||||
|
func (msg *TcActionMsg) write(b []byte) {
|
||||||
|
b[0] = msg.Family
|
||||||
|
copy(b[1:4], msg.Pad[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *TcActionMsg) serializeSafe() []byte {
|
||||||
|
length := SizeofTcActionMsg
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeTcActionMsgSafe(b []byte) *TcActionMsg {
|
||||||
|
var msg = TcActionMsg{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofTcActionMsg]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTcActionMsgDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofTcActionMsg)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeTcActionMsgSafe(orig)
|
||||||
|
msg := DeserializeTcActionMsg(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TcRateSpec */
|
||||||
|
func (msg *TcRateSpec) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
b[0] = msg.CellLog
|
||||||
|
b[1] = msg.Linklayer
|
||||||
|
native.PutUint16(b[2:4], msg.Overhead)
|
||||||
|
native.PutUint16(b[4:6], uint16(msg.CellAlign))
|
||||||
|
native.PutUint16(b[6:8], msg.Mpu)
|
||||||
|
native.PutUint32(b[8:12], msg.Rate)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *TcRateSpec) serializeSafe() []byte {
|
||||||
|
length := SizeofTcRateSpec
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeTcRateSpecSafe(b []byte) *TcRateSpec {
|
||||||
|
var msg = TcRateSpec{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofTcRateSpec]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTcRateSpecDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofTcRateSpec)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeTcRateSpecSafe(orig)
|
||||||
|
msg := DeserializeTcRateSpec(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TcTbfQopt */
|
||||||
|
func (msg *TcTbfQopt) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
msg.Rate.write(b[0:SizeofTcRateSpec])
|
||||||
|
start := SizeofTcRateSpec
|
||||||
|
msg.Peakrate.write(b[start : start+SizeofTcRateSpec])
|
||||||
|
start += SizeofTcRateSpec
|
||||||
|
native.PutUint32(b[start:start+4], msg.Limit)
|
||||||
|
start += 4
|
||||||
|
native.PutUint32(b[start:start+4], msg.Buffer)
|
||||||
|
start += 4
|
||||||
|
native.PutUint32(b[start:start+4], msg.Mtu)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *TcTbfQopt) serializeSafe() []byte {
|
||||||
|
length := SizeofTcTbfQopt
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeTcTbfQoptSafe(b []byte) *TcTbfQopt {
|
||||||
|
var msg = TcTbfQopt{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofTcTbfQopt]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTcTbfQoptDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofTcTbfQopt)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeTcTbfQoptSafe(orig)
|
||||||
|
msg := DeserializeTcTbfQopt(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TcHtbCopt */
|
||||||
|
func (msg *TcHtbCopt) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
msg.Rate.write(b[0:SizeofTcRateSpec])
|
||||||
|
start := SizeofTcRateSpec
|
||||||
|
msg.Ceil.write(b[start : start+SizeofTcRateSpec])
|
||||||
|
start += SizeofTcRateSpec
|
||||||
|
native.PutUint32(b[start:start+4], msg.Buffer)
|
||||||
|
start += 4
|
||||||
|
native.PutUint32(b[start:start+4], msg.Cbuffer)
|
||||||
|
start += 4
|
||||||
|
native.PutUint32(b[start:start+4], msg.Quantum)
|
||||||
|
start += 4
|
||||||
|
native.PutUint32(b[start:start+4], msg.Level)
|
||||||
|
start += 4
|
||||||
|
native.PutUint32(b[start:start+4], msg.Prio)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *TcHtbCopt) serializeSafe() []byte {
|
||||||
|
length := SizeofTcHtbCopt
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeTcHtbCoptSafe(b []byte) *TcHtbCopt {
|
||||||
|
var msg = TcHtbCopt{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofTcHtbCopt]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTcHtbCoptDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofTcHtbCopt)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeTcHtbCoptSafe(orig)
|
||||||
|
msg := DeserializeTcHtbCopt(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
161
vendor/github.com/vishvananda/netlink/nl/xfrm_linux_test.go
generated
vendored
Normal file
161
vendor/github.com/vishvananda/netlink/nl/xfrm_linux_test.go
generated
vendored
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
package nl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (msg *XfrmAddress) write(b []byte) {
|
||||||
|
copy(b[0:SizeofXfrmAddress], msg[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmAddress) serializeSafe() []byte {
|
||||||
|
b := make([]byte, SizeofXfrmAddress)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmAddressSafe(b []byte) *XfrmAddress {
|
||||||
|
var msg = XfrmAddress{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmAddress]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmAddressDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmAddress)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmAddressSafe(orig)
|
||||||
|
msg := DeserializeXfrmAddress(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmSelector) write(b []byte) {
|
||||||
|
const AddrEnd = SizeofXfrmAddress * 2
|
||||||
|
native := NativeEndian()
|
||||||
|
msg.Daddr.write(b[0:SizeofXfrmAddress])
|
||||||
|
msg.Saddr.write(b[SizeofXfrmAddress:AddrEnd])
|
||||||
|
native.PutUint16(b[AddrEnd:AddrEnd+2], msg.Dport)
|
||||||
|
native.PutUint16(b[AddrEnd+2:AddrEnd+4], msg.DportMask)
|
||||||
|
native.PutUint16(b[AddrEnd+4:AddrEnd+6], msg.Sport)
|
||||||
|
native.PutUint16(b[AddrEnd+6:AddrEnd+8], msg.SportMask)
|
||||||
|
native.PutUint16(b[AddrEnd+8:AddrEnd+10], msg.Family)
|
||||||
|
b[AddrEnd+10] = msg.PrefixlenD
|
||||||
|
b[AddrEnd+11] = msg.PrefixlenS
|
||||||
|
b[AddrEnd+12] = msg.Proto
|
||||||
|
copy(b[AddrEnd+13:AddrEnd+16], msg.Pad[:])
|
||||||
|
native.PutUint32(b[AddrEnd+16:AddrEnd+20], uint32(msg.Ifindex))
|
||||||
|
native.PutUint32(b[AddrEnd+20:AddrEnd+24], msg.User)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmSelector) serializeSafe() []byte {
|
||||||
|
length := SizeofXfrmSelector
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmSelectorSafe(b []byte) *XfrmSelector {
|
||||||
|
var msg = XfrmSelector{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmSelector]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmSelectorDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmSelector)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmSelectorSafe(orig)
|
||||||
|
msg := DeserializeXfrmSelector(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmLifetimeCfg) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
native.PutUint64(b[0:8], msg.SoftByteLimit)
|
||||||
|
native.PutUint64(b[8:16], msg.HardByteLimit)
|
||||||
|
native.PutUint64(b[16:24], msg.SoftPacketLimit)
|
||||||
|
native.PutUint64(b[24:32], msg.HardPacketLimit)
|
||||||
|
native.PutUint64(b[32:40], msg.SoftAddExpiresSeconds)
|
||||||
|
native.PutUint64(b[40:48], msg.HardAddExpiresSeconds)
|
||||||
|
native.PutUint64(b[48:56], msg.SoftUseExpiresSeconds)
|
||||||
|
native.PutUint64(b[56:64], msg.HardUseExpiresSeconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmLifetimeCfg) serializeSafe() []byte {
|
||||||
|
length := SizeofXfrmLifetimeCfg
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmLifetimeCfgSafe(b []byte) *XfrmLifetimeCfg {
|
||||||
|
var msg = XfrmLifetimeCfg{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmLifetimeCfg]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmLifetimeCfgDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmLifetimeCfg)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmLifetimeCfgSafe(orig)
|
||||||
|
msg := DeserializeXfrmLifetimeCfg(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmLifetimeCur) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
native.PutUint64(b[0:8], msg.Bytes)
|
||||||
|
native.PutUint64(b[8:16], msg.Packets)
|
||||||
|
native.PutUint64(b[16:24], msg.AddTime)
|
||||||
|
native.PutUint64(b[24:32], msg.UseTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmLifetimeCur) serializeSafe() []byte {
|
||||||
|
length := SizeofXfrmLifetimeCur
|
||||||
|
b := make([]byte, length)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmLifetimeCurSafe(b []byte) *XfrmLifetimeCur {
|
||||||
|
var msg = XfrmLifetimeCur{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmLifetimeCur]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmLifetimeCurDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmLifetimeCur)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmLifetimeCurSafe(orig)
|
||||||
|
msg := DeserializeXfrmLifetimeCur(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmId) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
msg.Daddr.write(b[0:SizeofXfrmAddress])
|
||||||
|
native.PutUint32(b[SizeofXfrmAddress:SizeofXfrmAddress+4], msg.Spi)
|
||||||
|
b[SizeofXfrmAddress+4] = msg.Proto
|
||||||
|
copy(b[SizeofXfrmAddress+5:SizeofXfrmAddress+8], msg.Pad[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmId) serializeSafe() []byte {
|
||||||
|
b := make([]byte, SizeofXfrmId)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmIdSafe(b []byte) *XfrmId {
|
||||||
|
var msg = XfrmId{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmId]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmIdDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmId)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmIdSafe(orig)
|
||||||
|
msg := DeserializeXfrmId(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
34
vendor/github.com/vishvananda/netlink/nl/xfrm_monitor_linux_test.go
generated
vendored
Normal file
34
vendor/github.com/vishvananda/netlink/nl/xfrm_monitor_linux_test.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package nl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (msg *XfrmUserExpire) write(b []byte) {
|
||||||
|
msg.XfrmUsersaInfo.write(b[0:SizeofXfrmUsersaInfo])
|
||||||
|
b[SizeofXfrmUsersaInfo] = msg.Hard
|
||||||
|
copy(b[SizeofXfrmUsersaInfo+1:SizeofXfrmUserExpire], msg.Pad[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmUserExpire) serializeSafe() []byte {
|
||||||
|
b := make([]byte, SizeofXfrmUserExpire)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmUserExpireSafe(b []byte) *XfrmUserExpire {
|
||||||
|
var msg = XfrmUserExpire{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmUserExpire]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmUserExpireDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmUserExpire)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmUserExpireSafe(orig)
|
||||||
|
msg := DeserializeXfrmUserExpire(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
109
vendor/github.com/vishvananda/netlink/nl/xfrm_policy_linux_test.go
generated
vendored
Normal file
109
vendor/github.com/vishvananda/netlink/nl/xfrm_policy_linux_test.go
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package nl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (msg *XfrmUserpolicyId) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
msg.Sel.write(b[0:SizeofXfrmSelector])
|
||||||
|
native.PutUint32(b[SizeofXfrmSelector:SizeofXfrmSelector+4], msg.Index)
|
||||||
|
b[SizeofXfrmSelector+4] = msg.Dir
|
||||||
|
copy(b[SizeofXfrmSelector+5:SizeofXfrmSelector+8], msg.Pad[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmUserpolicyId) serializeSafe() []byte {
|
||||||
|
b := make([]byte, SizeofXfrmUserpolicyId)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmUserpolicyIdSafe(b []byte) *XfrmUserpolicyId {
|
||||||
|
var msg = XfrmUserpolicyId{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmUserpolicyId]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmUserpolicyIdDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmUserpolicyId)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmUserpolicyIdSafe(orig)
|
||||||
|
msg := DeserializeXfrmUserpolicyId(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmUserpolicyInfo) write(b []byte) {
|
||||||
|
const CfgEnd = SizeofXfrmSelector + SizeofXfrmLifetimeCfg
|
||||||
|
const CurEnd = CfgEnd + SizeofXfrmLifetimeCur
|
||||||
|
native := NativeEndian()
|
||||||
|
msg.Sel.write(b[0:SizeofXfrmSelector])
|
||||||
|
msg.Lft.write(b[SizeofXfrmSelector:CfgEnd])
|
||||||
|
msg.Curlft.write(b[CfgEnd:CurEnd])
|
||||||
|
native.PutUint32(b[CurEnd:CurEnd+4], msg.Priority)
|
||||||
|
native.PutUint32(b[CurEnd+4:CurEnd+8], msg.Index)
|
||||||
|
b[CurEnd+8] = msg.Dir
|
||||||
|
b[CurEnd+9] = msg.Action
|
||||||
|
b[CurEnd+10] = msg.Flags
|
||||||
|
b[CurEnd+11] = msg.Share
|
||||||
|
copy(b[CurEnd+12:CurEnd+16], msg.Pad[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmUserpolicyInfo) serializeSafe() []byte {
|
||||||
|
b := make([]byte, SizeofXfrmUserpolicyInfo)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmUserpolicyInfoSafe(b []byte) *XfrmUserpolicyInfo {
|
||||||
|
var msg = XfrmUserpolicyInfo{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmUserpolicyInfo]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmUserpolicyInfoDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmUserpolicyInfo)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmUserpolicyInfoSafe(orig)
|
||||||
|
msg := DeserializeXfrmUserpolicyInfo(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmUserTmpl) write(b []byte) {
|
||||||
|
const AddrEnd = SizeofXfrmId + 4 + SizeofXfrmAddress
|
||||||
|
native := NativeEndian()
|
||||||
|
msg.XfrmId.write(b[0:SizeofXfrmId])
|
||||||
|
native.PutUint16(b[SizeofXfrmId:SizeofXfrmId+2], msg.Family)
|
||||||
|
copy(b[SizeofXfrmId+2:SizeofXfrmId+4], msg.Pad1[:])
|
||||||
|
msg.Saddr.write(b[SizeofXfrmId+4 : AddrEnd])
|
||||||
|
native.PutUint32(b[AddrEnd:AddrEnd+4], msg.Reqid)
|
||||||
|
b[AddrEnd+4] = msg.Mode
|
||||||
|
b[AddrEnd+5] = msg.Share
|
||||||
|
b[AddrEnd+6] = msg.Optional
|
||||||
|
b[AddrEnd+7] = msg.Pad2
|
||||||
|
native.PutUint32(b[AddrEnd+8:AddrEnd+12], msg.Aalgos)
|
||||||
|
native.PutUint32(b[AddrEnd+12:AddrEnd+16], msg.Ealgos)
|
||||||
|
native.PutUint32(b[AddrEnd+16:AddrEnd+20], msg.Calgos)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmUserTmpl) serializeSafe() []byte {
|
||||||
|
b := make([]byte, SizeofXfrmUserTmpl)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmUserTmplSafe(b []byte) *XfrmUserTmpl {
|
||||||
|
var msg = XfrmUserTmpl{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmUserTmpl]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmUserTmplDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmUserTmpl)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmUserTmplSafe(orig)
|
||||||
|
msg := DeserializeXfrmUserTmpl(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
304
vendor/github.com/vishvananda/netlink/nl/xfrm_state_linux_test.go
generated
vendored
Normal file
304
vendor/github.com/vishvananda/netlink/nl/xfrm_state_linux_test.go
generated
vendored
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
package nl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (msg *XfrmUsersaId) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
msg.Daddr.write(b[0:SizeofXfrmAddress])
|
||||||
|
native.PutUint32(b[SizeofXfrmAddress:SizeofXfrmAddress+4], msg.Spi)
|
||||||
|
native.PutUint16(b[SizeofXfrmAddress+4:SizeofXfrmAddress+6], msg.Family)
|
||||||
|
b[SizeofXfrmAddress+6] = msg.Proto
|
||||||
|
b[SizeofXfrmAddress+7] = msg.Pad
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmUsersaId) serializeSafe() []byte {
|
||||||
|
b := make([]byte, SizeofXfrmUsersaId)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmUsersaIdSafe(b []byte) *XfrmUsersaId {
|
||||||
|
var msg = XfrmUsersaId{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmUsersaId]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmUsersaIdDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmUsersaId)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmUsersaIdSafe(orig)
|
||||||
|
msg := DeserializeXfrmUsersaId(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmStats) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
native.PutUint32(b[0:4], msg.ReplayWindow)
|
||||||
|
native.PutUint32(b[4:8], msg.Replay)
|
||||||
|
native.PutUint32(b[8:12], msg.IntegrityFailed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmStats) serializeSafe() []byte {
|
||||||
|
b := make([]byte, SizeofXfrmStats)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmStatsSafe(b []byte) *XfrmStats {
|
||||||
|
var msg = XfrmStats{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmStats]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmStatsDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmStats)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmStatsSafe(orig)
|
||||||
|
msg := DeserializeXfrmStats(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmUsersaInfo) write(b []byte) {
|
||||||
|
const IdEnd = SizeofXfrmSelector + SizeofXfrmId
|
||||||
|
const AddressEnd = IdEnd + SizeofXfrmAddress
|
||||||
|
const CfgEnd = AddressEnd + SizeofXfrmLifetimeCfg
|
||||||
|
const CurEnd = CfgEnd + SizeofXfrmLifetimeCur
|
||||||
|
const StatsEnd = CurEnd + SizeofXfrmStats
|
||||||
|
native := NativeEndian()
|
||||||
|
msg.Sel.write(b[0:SizeofXfrmSelector])
|
||||||
|
msg.Id.write(b[SizeofXfrmSelector:IdEnd])
|
||||||
|
msg.Saddr.write(b[IdEnd:AddressEnd])
|
||||||
|
msg.Lft.write(b[AddressEnd:CfgEnd])
|
||||||
|
msg.Curlft.write(b[CfgEnd:CurEnd])
|
||||||
|
msg.Stats.write(b[CurEnd:StatsEnd])
|
||||||
|
native.PutUint32(b[StatsEnd:StatsEnd+4], msg.Seq)
|
||||||
|
native.PutUint32(b[StatsEnd+4:StatsEnd+8], msg.Reqid)
|
||||||
|
native.PutUint16(b[StatsEnd+8:StatsEnd+10], msg.Family)
|
||||||
|
b[StatsEnd+10] = msg.Mode
|
||||||
|
b[StatsEnd+11] = msg.ReplayWindow
|
||||||
|
b[StatsEnd+12] = msg.Flags
|
||||||
|
copy(b[StatsEnd+13:StatsEnd+20], msg.Pad[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmUsersaInfo) serializeSafe() []byte {
|
||||||
|
b := make([]byte, SizeofXfrmUsersaInfo)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmUsersaInfoSafe(b []byte) *XfrmUsersaInfo {
|
||||||
|
var msg = XfrmUsersaInfo{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmUsersaInfo]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmUsersaInfoDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmUsersaInfo)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmUsersaInfoSafe(orig)
|
||||||
|
msg := DeserializeXfrmUsersaInfo(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmAlgo) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
copy(b[0:64], msg.AlgName[:])
|
||||||
|
native.PutUint32(b[64:68], msg.AlgKeyLen)
|
||||||
|
copy(b[68:msg.Len()], msg.AlgKey[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmAlgo) serializeSafe() []byte {
|
||||||
|
b := make([]byte, msg.Len())
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmUserSpiInfo) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
msg.XfrmUsersaInfo.write(b[0:SizeofXfrmUsersaInfo])
|
||||||
|
native.PutUint32(b[SizeofXfrmUsersaInfo:SizeofXfrmUsersaInfo+4], msg.Min)
|
||||||
|
native.PutUint32(b[SizeofXfrmUsersaInfo+4:SizeofXfrmUsersaInfo+8], msg.Max)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmUserSpiInfo) serializeSafe() []byte {
|
||||||
|
b := make([]byte, SizeofXfrmUserSpiInfo)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmUserSpiInfoSafe(b []byte) *XfrmUserSpiInfo {
|
||||||
|
var msg = XfrmUserSpiInfo{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmUserSpiInfo]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmUserSpiInfoDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmUserSpiInfo)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmUserSpiInfoSafe(orig)
|
||||||
|
msg := DeserializeXfrmUserSpiInfo(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmAlgoSafe(b []byte) *XfrmAlgo {
|
||||||
|
var msg = XfrmAlgo{}
|
||||||
|
copy(msg.AlgName[:], b[0:64])
|
||||||
|
binary.Read(bytes.NewReader(b[64:68]), NativeEndian(), &msg.AlgKeyLen)
|
||||||
|
msg.AlgKey = b[68:msg.Len()]
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmAlgoDeserializeSerialize(t *testing.T) {
|
||||||
|
native := NativeEndian()
|
||||||
|
// use a 32 byte key len
|
||||||
|
var orig = make([]byte, SizeofXfrmAlgo+32)
|
||||||
|
rand.Read(orig)
|
||||||
|
// set the key len to 256 bits
|
||||||
|
var KeyLen uint32 = 0x00000100
|
||||||
|
// Little Endian Big Endian
|
||||||
|
// orig[64] = 0 orig[64] = 0
|
||||||
|
// orig[65] = 1 orig[65] = 0
|
||||||
|
// orig[66] = 0 orig[66] = 1
|
||||||
|
// orig[67] = 0 orig[67] = 0
|
||||||
|
native.PutUint32(orig[64:68], KeyLen)
|
||||||
|
safemsg := deserializeXfrmAlgoSafe(orig)
|
||||||
|
msg := DeserializeXfrmAlgo(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmAlgoAuth) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
copy(b[0:64], msg.AlgName[:])
|
||||||
|
native.PutUint32(b[64:68], msg.AlgKeyLen)
|
||||||
|
native.PutUint32(b[68:72], msg.AlgTruncLen)
|
||||||
|
copy(b[72:msg.Len()], msg.AlgKey[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmAlgoAuth) serializeSafe() []byte {
|
||||||
|
b := make([]byte, msg.Len())
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmAlgoAuthSafe(b []byte) *XfrmAlgoAuth {
|
||||||
|
var msg = XfrmAlgoAuth{}
|
||||||
|
copy(msg.AlgName[:], b[0:64])
|
||||||
|
binary.Read(bytes.NewReader(b[64:68]), NativeEndian(), &msg.AlgKeyLen)
|
||||||
|
binary.Read(bytes.NewReader(b[68:72]), NativeEndian(), &msg.AlgTruncLen)
|
||||||
|
msg.AlgKey = b[72:msg.Len()]
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmAlgoAuthDeserializeSerialize(t *testing.T) {
|
||||||
|
native := NativeEndian()
|
||||||
|
// use a 32 byte key len
|
||||||
|
var orig = make([]byte, SizeofXfrmAlgoAuth+32)
|
||||||
|
rand.Read(orig)
|
||||||
|
// set the key len to 256 bits
|
||||||
|
var KeyLen uint32 = 0x00000100
|
||||||
|
// Little Endian Big Endian
|
||||||
|
// orig[64] = 0 orig[64] = 0
|
||||||
|
// orig[65] = 1 orig[65] = 0
|
||||||
|
// orig[66] = 0 orig[66] = 1
|
||||||
|
// orig[67] = 0 orig[67] = 0
|
||||||
|
native.PutUint32(orig[64:68], KeyLen)
|
||||||
|
safemsg := deserializeXfrmAlgoAuthSafe(orig)
|
||||||
|
msg := DeserializeXfrmAlgoAuth(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmEncapTmpl) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
native.PutUint16(b[0:2], msg.EncapType)
|
||||||
|
native.PutUint16(b[2:4], msg.EncapSport)
|
||||||
|
native.PutUint16(b[4:6], msg.EncapDport)
|
||||||
|
copy(b[6:8], msg.Pad[:])
|
||||||
|
msg.EncapOa.write(b[8:SizeofXfrmAddress])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmEncapTmpl) serializeSafe() []byte {
|
||||||
|
b := make([]byte, SizeofXfrmEncapTmpl)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmEncapTmplSafe(b []byte) *XfrmEncapTmpl {
|
||||||
|
var msg = XfrmEncapTmpl{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmEncapTmpl]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmEncapTmplDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmEncapTmpl)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmEncapTmplSafe(orig)
|
||||||
|
msg := DeserializeXfrmEncapTmpl(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmMark) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
native.PutUint32(b[0:4], msg.Value)
|
||||||
|
native.PutUint32(b[4:8], msg.Mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmMark) serializeSafe() []byte {
|
||||||
|
b := make([]byte, SizeofXfrmMark)
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmMarkSafe(b []byte) *XfrmMark {
|
||||||
|
var msg = XfrmMark{}
|
||||||
|
binary.Read(bytes.NewReader(b[0:SizeofXfrmMark]), NativeEndian(), &msg)
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmMarkDeserializeSerialize(t *testing.T) {
|
||||||
|
var orig = make([]byte, SizeofXfrmMark)
|
||||||
|
rand.Read(orig)
|
||||||
|
safemsg := deserializeXfrmMarkSafe(orig)
|
||||||
|
msg := DeserializeXfrmMark(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmAlgoAEAD) write(b []byte) {
|
||||||
|
native := NativeEndian()
|
||||||
|
copy(b[0:64], msg.AlgName[:])
|
||||||
|
native.PutUint32(b[64:68], msg.AlgKeyLen)
|
||||||
|
native.PutUint32(b[68:72], msg.AlgICVLen)
|
||||||
|
copy(b[72:msg.Len()], msg.AlgKey[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *XfrmAlgoAEAD) serializeSafe() []byte {
|
||||||
|
b := make([]byte, msg.Len())
|
||||||
|
msg.write(b)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeXfrmAlgoAEADSafe(b []byte) *XfrmAlgoAEAD {
|
||||||
|
var msg = XfrmAlgoAEAD{}
|
||||||
|
copy(msg.AlgName[:], b[0:64])
|
||||||
|
binary.Read(bytes.NewReader(b[64:68]), NativeEndian(), &msg.AlgKeyLen)
|
||||||
|
binary.Read(bytes.NewReader(b[68:72]), NativeEndian(), &msg.AlgICVLen)
|
||||||
|
msg.AlgKey = b[72:msg.Len()]
|
||||||
|
return &msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmXfrmAlgoAeadDeserializeSerialize(t *testing.T) {
|
||||||
|
native := NativeEndian()
|
||||||
|
// use a 32 byte key len
|
||||||
|
var orig = make([]byte, SizeofXfrmAlgoAEAD+36)
|
||||||
|
rand.Read(orig)
|
||||||
|
// set the key len to (256 + 32) bits
|
||||||
|
var KeyLen uint32 = 0x00000120
|
||||||
|
native.PutUint32(orig[64:68], KeyLen)
|
||||||
|
safemsg := deserializeXfrmAlgoAEADSafe(orig)
|
||||||
|
msg := DeserializeXfrmAlgoAEAD(orig)
|
||||||
|
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||||
|
}
|
20
vendor/github.com/vishvananda/netlink/protinfo.go
generated
vendored
20
vendor/github.com/vishvananda/netlink/protinfo.go
generated
vendored
@ -6,12 +6,14 @@ import (
|
|||||||
|
|
||||||
// Protinfo represents bridge flags from netlink.
|
// Protinfo represents bridge flags from netlink.
|
||||||
type Protinfo struct {
|
type Protinfo struct {
|
||||||
Hairpin bool
|
Hairpin bool
|
||||||
Guard bool
|
Guard bool
|
||||||
FastLeave bool
|
FastLeave bool
|
||||||
RootBlock bool
|
RootBlock bool
|
||||||
Learning bool
|
Learning bool
|
||||||
Flood bool
|
Flood bool
|
||||||
|
ProxyArp bool
|
||||||
|
ProxyArpWiFi bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a list of enabled flags
|
// String returns a list of enabled flags
|
||||||
@ -35,6 +37,12 @@ func (prot *Protinfo) String() string {
|
|||||||
if prot.Flood {
|
if prot.Flood {
|
||||||
boolStrings = append(boolStrings, "Flood")
|
boolStrings = append(boolStrings, "Flood")
|
||||||
}
|
}
|
||||||
|
if prot.ProxyArp {
|
||||||
|
boolStrings = append(boolStrings, "ProxyArp")
|
||||||
|
}
|
||||||
|
if prot.ProxyArpWiFi {
|
||||||
|
boolStrings = append(boolStrings, "ProxyArpWiFi")
|
||||||
|
}
|
||||||
return strings.Join(boolStrings, " ")
|
return strings.Join(boolStrings, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
vendor/github.com/vishvananda/netlink/protinfo_linux.go
generated
vendored
4
vendor/github.com/vishvananda/netlink/protinfo_linux.go
generated
vendored
@ -64,6 +64,10 @@ func parseProtinfo(infos []syscall.NetlinkRouteAttr) *Protinfo {
|
|||||||
pi.Learning = byteToBool(info.Value[0])
|
pi.Learning = byteToBool(info.Value[0])
|
||||||
case nl.IFLA_BRPORT_UNICAST_FLOOD:
|
case nl.IFLA_BRPORT_UNICAST_FLOOD:
|
||||||
pi.Flood = byteToBool(info.Value[0])
|
pi.Flood = byteToBool(info.Value[0])
|
||||||
|
case nl.IFLA_BRPORT_PROXYARP:
|
||||||
|
pi.ProxyArp = byteToBool(info.Value[0])
|
||||||
|
case nl.IFLA_BRPORT_PROXYARP_WIFI:
|
||||||
|
pi.ProxyArpWiFi = byteToBool(info.Value[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &pi
|
return &pi
|
||||||
|
163
vendor/github.com/vishvananda/netlink/protinfo_test.go
generated
vendored
Normal file
163
vendor/github.com/vishvananda/netlink/protinfo_test.go
generated
vendored
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProtinfo(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
master := &Bridge{LinkAttrs{Name: "foo"}}
|
||||||
|
if err := LinkAdd(master); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
iface1 := &Dummy{LinkAttrs{Name: "bar1", MasterIndex: master.Index}}
|
||||||
|
iface2 := &Dummy{LinkAttrs{Name: "bar2", MasterIndex: master.Index}}
|
||||||
|
iface3 := &Dummy{LinkAttrs{Name: "bar3"}}
|
||||||
|
iface4 := &Dummy{LinkAttrs{Name: "bar4", MasterIndex: master.Index}}
|
||||||
|
|
||||||
|
if err := LinkAdd(iface1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkAdd(iface2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkAdd(iface3); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkAdd(iface4); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldpi1, err := LinkGetProtinfo(iface1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
oldpi2, err := LinkGetProtinfo(iface2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
oldpi4, err := LinkGetProtinfo(iface4)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := LinkSetHairpin(iface1, true); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := LinkSetRootBlock(iface1, true); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pi1, err := LinkGetProtinfo(iface1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !pi1.Hairpin {
|
||||||
|
t.Fatalf("Hairpin mode is not enabled for %s, but should", iface1.Name)
|
||||||
|
}
|
||||||
|
if !pi1.RootBlock {
|
||||||
|
t.Fatalf("RootBlock is not enabled for %s, but should", iface1.Name)
|
||||||
|
}
|
||||||
|
if pi1.ProxyArp != oldpi1.ProxyArp {
|
||||||
|
t.Fatalf("ProxyArp field was changed for %s but shouldn't", iface1.Name)
|
||||||
|
}
|
||||||
|
if pi1.ProxyArpWiFi != oldpi1.ProxyArp {
|
||||||
|
t.Fatalf("ProxyArpWiFi ProxyArp field was changed for %s but shouldn't", iface1.Name)
|
||||||
|
}
|
||||||
|
if pi1.Guard != oldpi1.Guard {
|
||||||
|
t.Fatalf("Guard field was changed for %s but shouldn't", iface1.Name)
|
||||||
|
}
|
||||||
|
if pi1.FastLeave != oldpi1.FastLeave {
|
||||||
|
t.Fatalf("FastLeave field was changed for %s but shouldn't", iface1.Name)
|
||||||
|
}
|
||||||
|
if pi1.Learning != oldpi1.Learning {
|
||||||
|
t.Fatalf("Learning field was changed for %s but shouldn't", iface1.Name)
|
||||||
|
}
|
||||||
|
if pi1.Flood != oldpi1.Flood {
|
||||||
|
t.Fatalf("Flood field was changed for %s but shouldn't", iface1.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := LinkSetGuard(iface2, true); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetLearning(iface2, false); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
pi2, err := LinkGetProtinfo(iface2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if pi2.Hairpin {
|
||||||
|
t.Fatalf("Hairpin mode is enabled for %s, but shouldn't", iface2.Name)
|
||||||
|
}
|
||||||
|
if !pi2.Guard {
|
||||||
|
t.Fatalf("Guard is not enabled for %s, but should", iface2.Name)
|
||||||
|
}
|
||||||
|
if pi2.ProxyArp != oldpi2.ProxyArp {
|
||||||
|
t.Fatalf("ProxyArp field was changed for %s but shouldn't", iface2.Name)
|
||||||
|
}
|
||||||
|
if pi2.ProxyArpWiFi != oldpi2.ProxyArpWiFi {
|
||||||
|
t.Fatalf("ProxyArpWiFi field was changed for %s but shouldn't", iface2.Name)
|
||||||
|
}
|
||||||
|
if pi2.Learning {
|
||||||
|
t.Fatalf("Learning is enabled for %s, but shouldn't", iface2.Name)
|
||||||
|
}
|
||||||
|
if pi2.RootBlock != oldpi2.RootBlock {
|
||||||
|
t.Fatalf("RootBlock field was changed for %s but shouldn't", iface2.Name)
|
||||||
|
}
|
||||||
|
if pi2.FastLeave != oldpi2.FastLeave {
|
||||||
|
t.Fatalf("FastLeave field was changed for %s but shouldn't", iface2.Name)
|
||||||
|
}
|
||||||
|
if pi2.Flood != oldpi2.Flood {
|
||||||
|
t.Fatalf("Flood field was changed for %s but shouldn't", iface2.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := LinkSetHairpin(iface3, true); err == nil || err.Error() != "operation not supported" {
|
||||||
|
t.Fatalf("Set protinfo attrs for link without master is not supported, but err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.Getenv("TRAVIS_BUILD_DIR") != "" {
|
||||||
|
t.Skipf("Skipped some tests because travis kernel is to old to support BR_PROXYARP.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := LinkSetBrProxyArp(iface4, true); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := LinkSetBrProxyArpWiFi(iface4, true); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
pi4, err := LinkGetProtinfo(iface4)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if pi4.Hairpin != oldpi4.Hairpin {
|
||||||
|
t.Fatalf("Hairpin field was changed for %s but shouldn't", iface4.Name)
|
||||||
|
}
|
||||||
|
if pi4.Guard != oldpi4.Guard {
|
||||||
|
t.Fatalf("Guard field was changed for %s but shouldn't", iface4.Name)
|
||||||
|
}
|
||||||
|
if pi4.Learning != oldpi4.Learning {
|
||||||
|
t.Fatalf("Learning field was changed for %s but shouldn't", iface4.Name)
|
||||||
|
}
|
||||||
|
if !pi4.ProxyArp {
|
||||||
|
t.Fatalf("ProxyArp is not enabled for %s, but should", iface4.Name)
|
||||||
|
}
|
||||||
|
if !pi4.ProxyArpWiFi {
|
||||||
|
t.Fatalf("ProxyArpWiFi is not enabled for %s, but should", iface4.Name)
|
||||||
|
}
|
||||||
|
if pi4.RootBlock != oldpi4.RootBlock {
|
||||||
|
t.Fatalf("RootBlock field was changed for %s but shouldn't", iface4.Name)
|
||||||
|
}
|
||||||
|
if pi4.FastLeave != oldpi4.FastLeave {
|
||||||
|
t.Fatalf("FastLeave field was changed for %s but shouldn't", iface4.Name)
|
||||||
|
}
|
||||||
|
if pi4.Flood != oldpi4.Flood {
|
||||||
|
t.Fatalf("Flood field was changed for %s but shouldn't", iface4.Name)
|
||||||
|
}
|
||||||
|
}
|
347
vendor/github.com/vishvananda/netlink/qdisc_test.go
generated
vendored
Normal file
347
vendor/github.com/vishvananda/netlink/qdisc_test.go
generated
vendored
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTbfAddDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdisc := &Tbf{
|
||||||
|
QdiscAttrs: QdiscAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Handle: MakeHandle(1, 0),
|
||||||
|
Parent: HANDLE_ROOT,
|
||||||
|
},
|
||||||
|
Rate: 131072,
|
||||||
|
Limit: 1220703,
|
||||||
|
Buffer: 16793,
|
||||||
|
}
|
||||||
|
if err := QdiscAdd(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err := QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
tbf, ok := qdiscs[0].(*Tbf)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
if tbf.Rate != qdisc.Rate {
|
||||||
|
t.Fatal("Rate doesn't match")
|
||||||
|
}
|
||||||
|
if tbf.Limit != qdisc.Limit {
|
||||||
|
t.Fatal("Limit doesn't match")
|
||||||
|
}
|
||||||
|
if tbf.Buffer != qdisc.Buffer {
|
||||||
|
t.Fatal("Buffer doesn't match")
|
||||||
|
}
|
||||||
|
if err := QdiscDel(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 0 {
|
||||||
|
t.Fatal("Failed to remove qdisc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHtbAddDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs := QdiscAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Handle: MakeHandle(1, 0),
|
||||||
|
Parent: HANDLE_ROOT,
|
||||||
|
}
|
||||||
|
|
||||||
|
qdisc := NewHtb(attrs)
|
||||||
|
qdisc.Rate2Quantum = 5
|
||||||
|
if err := QdiscAdd(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
qdiscs, err := QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
htb, ok := qdiscs[0].(*Htb)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
if htb.Defcls != qdisc.Defcls {
|
||||||
|
t.Fatal("Defcls doesn't match")
|
||||||
|
}
|
||||||
|
if htb.Rate2Quantum != qdisc.Rate2Quantum {
|
||||||
|
t.Fatal("Rate2Quantum doesn't match")
|
||||||
|
}
|
||||||
|
if htb.Debug != qdisc.Debug {
|
||||||
|
t.Fatal("Debug doesn't match")
|
||||||
|
}
|
||||||
|
if err := QdiscDel(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 0 {
|
||||||
|
t.Fatal("Failed to remove qdisc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrioAddDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdisc := NewPrio(QdiscAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Handle: MakeHandle(1, 0),
|
||||||
|
Parent: HANDLE_ROOT,
|
||||||
|
})
|
||||||
|
if err := QdiscAdd(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err := QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
_, ok := qdiscs[0].(*Prio)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
if err := QdiscDel(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 0 {
|
||||||
|
t.Fatal("Failed to remove qdisc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTbfAddHtbReplaceDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add
|
||||||
|
attrs := QdiscAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Handle: MakeHandle(1, 0),
|
||||||
|
Parent: HANDLE_ROOT,
|
||||||
|
}
|
||||||
|
qdisc := &Tbf{
|
||||||
|
QdiscAttrs: attrs,
|
||||||
|
Rate: 131072,
|
||||||
|
Limit: 1220703,
|
||||||
|
Buffer: 16793,
|
||||||
|
}
|
||||||
|
if err := QdiscAdd(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err := QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
tbf, ok := qdiscs[0].(*Tbf)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
if tbf.Rate != qdisc.Rate {
|
||||||
|
t.Fatal("Rate doesn't match")
|
||||||
|
}
|
||||||
|
if tbf.Limit != qdisc.Limit {
|
||||||
|
t.Fatal("Limit doesn't match")
|
||||||
|
}
|
||||||
|
if tbf.Buffer != qdisc.Buffer {
|
||||||
|
t.Fatal("Buffer doesn't match")
|
||||||
|
}
|
||||||
|
// Replace
|
||||||
|
// For replace to work, the handle MUST be different that the running one
|
||||||
|
attrs.Handle = MakeHandle(2, 0)
|
||||||
|
qdisc2 := NewHtb(attrs)
|
||||||
|
qdisc2.Rate2Quantum = 5
|
||||||
|
if err := QdiscReplace(qdisc2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
htb, ok := qdiscs[0].(*Htb)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
if htb.Defcls != qdisc2.Defcls {
|
||||||
|
t.Fatal("Defcls doesn't match")
|
||||||
|
}
|
||||||
|
if htb.Rate2Quantum != qdisc2.Rate2Quantum {
|
||||||
|
t.Fatal("Rate2Quantum doesn't match")
|
||||||
|
}
|
||||||
|
if htb.Debug != qdisc2.Debug {
|
||||||
|
t.Fatal("Debug doesn't match")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := QdiscDel(qdisc2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 0 {
|
||||||
|
t.Fatal("Failed to remove qdisc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTbfAddTbfChangeDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add
|
||||||
|
attrs := QdiscAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Handle: MakeHandle(1, 0),
|
||||||
|
Parent: HANDLE_ROOT,
|
||||||
|
}
|
||||||
|
qdisc := &Tbf{
|
||||||
|
QdiscAttrs: attrs,
|
||||||
|
Rate: 131072,
|
||||||
|
Limit: 1220703,
|
||||||
|
Buffer: 16793,
|
||||||
|
}
|
||||||
|
if err := QdiscAdd(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err := QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
tbf, ok := qdiscs[0].(*Tbf)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
if tbf.Rate != qdisc.Rate {
|
||||||
|
t.Fatal("Rate doesn't match")
|
||||||
|
}
|
||||||
|
if tbf.Limit != qdisc.Limit {
|
||||||
|
t.Fatal("Limit doesn't match")
|
||||||
|
}
|
||||||
|
if tbf.Buffer != qdisc.Buffer {
|
||||||
|
t.Fatal("Buffer doesn't match")
|
||||||
|
}
|
||||||
|
// Change
|
||||||
|
// For change to work, the handle MUST not change
|
||||||
|
qdisc.Rate = 23456
|
||||||
|
if err := QdiscChange(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
tbf, ok = qdiscs[0].(*Tbf)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
if tbf.Rate != qdisc.Rate {
|
||||||
|
t.Fatal("Rate doesn't match")
|
||||||
|
}
|
||||||
|
if tbf.Limit != qdisc.Limit {
|
||||||
|
t.Fatal("Limit doesn't match")
|
||||||
|
}
|
||||||
|
if tbf.Buffer != qdisc.Buffer {
|
||||||
|
t.Fatal("Buffer doesn't match")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := QdiscDel(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err = QdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 0 {
|
||||||
|
t.Fatal("Failed to remove qdisc")
|
||||||
|
}
|
||||||
|
}
|
500
vendor/github.com/vishvananda/netlink/route_test.go
generated
vendored
Normal file
500
vendor/github.com/vishvananda/netlink/route_test.go
generated
vendored
Normal file
@ -0,0 +1,500 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/vishvananda/netns"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRouteAddDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
// get loopback interface
|
||||||
|
link, err := LinkByName("lo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bring the interface up
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a gateway route
|
||||||
|
dst := &net.IPNet{
|
||||||
|
IP: net.IPv4(192, 168, 0, 0),
|
||||||
|
Mask: net.CIDRMask(24, 32),
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := net.IPv4(127, 1, 1, 1)
|
||||||
|
route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
|
||||||
|
if err := RouteAdd(&route); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
routes, err := RouteList(link, FAMILY_V4)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(routes) != 1 {
|
||||||
|
t.Fatal("Route not added properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
dstIP := net.IPv4(192, 168, 0, 42)
|
||||||
|
routeToDstIP, err := RouteGet(dstIP)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(routeToDstIP) == 0 {
|
||||||
|
t.Fatal("Default route not present")
|
||||||
|
}
|
||||||
|
if err := RouteDel(&route); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
routes, err = RouteList(link, FAMILY_V4)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(routes) != 0 {
|
||||||
|
t.Fatal("Route not removed properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRouteReplace(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
// get loopback interface
|
||||||
|
link, err := LinkByName("lo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bring the interface up
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a gateway route
|
||||||
|
dst := &net.IPNet{
|
||||||
|
IP: net.IPv4(192, 168, 0, 0),
|
||||||
|
Mask: net.CIDRMask(24, 32),
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := net.IPv4(127, 1, 1, 1)
|
||||||
|
route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
|
||||||
|
if err := RouteAdd(&route); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
routes, err := RouteList(link, FAMILY_V4)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(routes) != 1 {
|
||||||
|
t.Fatal("Route not added properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
ip = net.IPv4(127, 1, 1, 2)
|
||||||
|
route = Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
|
||||||
|
if err := RouteReplace(&route); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
routes, err = RouteList(link, FAMILY_V4)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(routes) != 1 || !routes[0].Src.Equal(ip) {
|
||||||
|
t.Fatal("Route not replaced properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := RouteDel(&route); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
routes, err = RouteList(link, FAMILY_V4)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(routes) != 0 {
|
||||||
|
t.Fatal("Route not removed properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRouteAddIncomplete(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
// get loopback interface
|
||||||
|
link, err := LinkByName("lo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bring the interface up
|
||||||
|
if err = LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
route := Route{LinkIndex: link.Attrs().Index}
|
||||||
|
if err := RouteAdd(&route); err == nil {
|
||||||
|
t.Fatal("Adding incomplete route should fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectRouteUpdate(ch <-chan RouteUpdate, t uint16, dst net.IP) bool {
|
||||||
|
for {
|
||||||
|
timeout := time.After(time.Minute)
|
||||||
|
select {
|
||||||
|
case update := <-ch:
|
||||||
|
if update.Type == t && update.Route.Dst.IP.Equal(dst) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case <-timeout:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRouteSubscribe(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
ch := make(chan RouteUpdate)
|
||||||
|
done := make(chan struct{})
|
||||||
|
defer close(done)
|
||||||
|
if err := RouteSubscribe(ch, done); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get loopback interface
|
||||||
|
link, err := LinkByName("lo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bring the interface up
|
||||||
|
if err = LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a gateway route
|
||||||
|
dst := &net.IPNet{
|
||||||
|
IP: net.IPv4(192, 168, 0, 0),
|
||||||
|
Mask: net.CIDRMask(24, 32),
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := net.IPv4(127, 1, 1, 1)
|
||||||
|
route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
|
||||||
|
if err := RouteAdd(&route); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !expectRouteUpdate(ch, syscall.RTM_NEWROUTE, dst.IP) {
|
||||||
|
t.Fatal("Add update not received as expected")
|
||||||
|
}
|
||||||
|
if err := RouteDel(&route); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !expectRouteUpdate(ch, syscall.RTM_DELROUTE, dst.IP) {
|
||||||
|
t.Fatal("Del update not received as expected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRouteSubscribeAt(t *testing.T) {
|
||||||
|
skipUnlessRoot(t)
|
||||||
|
|
||||||
|
// Create an handle on a custom netns
|
||||||
|
newNs, err := netns.New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer newNs.Close()
|
||||||
|
|
||||||
|
nh, err := NewHandleAt(newNs)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer nh.Delete()
|
||||||
|
|
||||||
|
// Subscribe for Route events on the custom netns
|
||||||
|
ch := make(chan RouteUpdate)
|
||||||
|
done := make(chan struct{})
|
||||||
|
defer close(done)
|
||||||
|
if err := RouteSubscribeAt(newNs, ch, done); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get loopback interface
|
||||||
|
link, err := nh.LinkByName("lo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bring the interface up
|
||||||
|
if err = nh.LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a gateway route
|
||||||
|
dst := &net.IPNet{
|
||||||
|
IP: net.IPv4(192, 169, 0, 0),
|
||||||
|
Mask: net.CIDRMask(24, 32),
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := net.IPv4(127, 100, 1, 1)
|
||||||
|
route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
|
||||||
|
if err := nh.RouteAdd(&route); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !expectRouteUpdate(ch, syscall.RTM_NEWROUTE, dst.IP) {
|
||||||
|
t.Fatal("Add update not received as expected")
|
||||||
|
}
|
||||||
|
if err := nh.RouteDel(&route); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !expectRouteUpdate(ch, syscall.RTM_DELROUTE, dst.IP) {
|
||||||
|
t.Fatal("Del update not received as expected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRouteExtraFields(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
// get loopback interface
|
||||||
|
link, err := LinkByName("lo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// bring the interface up
|
||||||
|
if err = LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a gateway route
|
||||||
|
dst := &net.IPNet{
|
||||||
|
IP: net.IPv4(1, 1, 1, 1),
|
||||||
|
Mask: net.CIDRMask(32, 32),
|
||||||
|
}
|
||||||
|
|
||||||
|
src := net.IPv4(127, 3, 3, 3)
|
||||||
|
route := Route{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Dst: dst,
|
||||||
|
Src: src,
|
||||||
|
Scope: syscall.RT_SCOPE_LINK,
|
||||||
|
Priority: 13,
|
||||||
|
Table: syscall.RT_TABLE_MAIN,
|
||||||
|
Type: syscall.RTN_UNICAST,
|
||||||
|
Tos: 14,
|
||||||
|
}
|
||||||
|
if err := RouteAdd(&route); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
routes, err := RouteListFiltered(FAMILY_V4, &Route{
|
||||||
|
Dst: dst,
|
||||||
|
Src: src,
|
||||||
|
Scope: syscall.RT_SCOPE_LINK,
|
||||||
|
Table: syscall.RT_TABLE_MAIN,
|
||||||
|
Type: syscall.RTN_UNICAST,
|
||||||
|
Tos: 14,
|
||||||
|
}, RT_FILTER_DST|RT_FILTER_SRC|RT_FILTER_SCOPE|RT_FILTER_TABLE|RT_FILTER_TYPE|RT_FILTER_TOS)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(routes) != 1 {
|
||||||
|
t.Fatal("Route not added properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
if routes[0].Scope != syscall.RT_SCOPE_LINK {
|
||||||
|
t.Fatal("Invalid Scope. Route not added properly")
|
||||||
|
}
|
||||||
|
if routes[0].Priority != 13 {
|
||||||
|
t.Fatal("Invalid Priority. Route not added properly")
|
||||||
|
}
|
||||||
|
if routes[0].Table != syscall.RT_TABLE_MAIN {
|
||||||
|
t.Fatal("Invalid Scope. Route not added properly")
|
||||||
|
}
|
||||||
|
if routes[0].Type != syscall.RTN_UNICAST {
|
||||||
|
t.Fatal("Invalid Type. Route not added properly")
|
||||||
|
}
|
||||||
|
if routes[0].Tos != 14 {
|
||||||
|
t.Fatal("Invalid Tos. Route not added properly")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRouteMultiPath(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
// get loopback interface
|
||||||
|
link, err := LinkByName("lo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// bring the interface up
|
||||||
|
if err = LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a gateway route
|
||||||
|
dst := &net.IPNet{
|
||||||
|
IP: net.IPv4(192, 168, 0, 0),
|
||||||
|
Mask: net.CIDRMask(24, 32),
|
||||||
|
}
|
||||||
|
|
||||||
|
idx := link.Attrs().Index
|
||||||
|
route := Route{Dst: dst, MultiPath: []*NexthopInfo{&NexthopInfo{LinkIndex: idx}, &NexthopInfo{LinkIndex: idx}}}
|
||||||
|
if err := RouteAdd(&route); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
routes, err := RouteList(nil, FAMILY_V4)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(routes) != 1 {
|
||||||
|
t.Fatal("MultiPath Route not added properly")
|
||||||
|
}
|
||||||
|
if len(routes[0].MultiPath) != 2 {
|
||||||
|
t.Fatal("MultiPath Route not added properly")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterDefaultRoute(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
// get loopback interface
|
||||||
|
link, err := LinkByName("lo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// bring the interface up
|
||||||
|
if err = LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
address := &Addr{
|
||||||
|
IPNet: &net.IPNet{
|
||||||
|
IP: net.IPv4(127, 0, 0, 2),
|
||||||
|
Mask: net.CIDRMask(24, 32),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err = AddrAdd(link, address); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add default route
|
||||||
|
gw := net.IPv4(127, 0, 0, 2)
|
||||||
|
|
||||||
|
defaultRoute := Route{
|
||||||
|
Dst: nil,
|
||||||
|
Gw: gw,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := RouteAdd(&defaultRoute); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add an extra route
|
||||||
|
dst := &net.IPNet{
|
||||||
|
IP: net.IPv4(192, 168, 0, 0),
|
||||||
|
Mask: net.CIDRMask(24, 32),
|
||||||
|
}
|
||||||
|
|
||||||
|
extraRoute := Route{
|
||||||
|
Dst: dst,
|
||||||
|
Gw: gw,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := RouteAdd(&extraRoute); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var filterTests = []struct {
|
||||||
|
filter *Route
|
||||||
|
mask uint64
|
||||||
|
expected net.IP
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
&Route{Dst: nil},
|
||||||
|
RT_FILTER_DST,
|
||||||
|
gw,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Route{Dst: dst},
|
||||||
|
RT_FILTER_DST,
|
||||||
|
gw,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range filterTests {
|
||||||
|
routes, err := RouteListFiltered(FAMILY_V4, f.filter, f.mask)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(routes) != 1 {
|
||||||
|
t.Fatal("Route not filtered properly")
|
||||||
|
}
|
||||||
|
if !routes[0].Gw.Equal(gw) {
|
||||||
|
t.Fatal("Unexpected Gateway")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMPLSRouteAddDel(t *testing.T) {
|
||||||
|
tearDown := setUpMPLSNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
// get loopback interface
|
||||||
|
link, err := LinkByName("lo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bring the interface up
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mplsDst := 100
|
||||||
|
route := Route{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
MPLSDst: &mplsDst,
|
||||||
|
NewDst: &MPLSDestination{
|
||||||
|
Labels: []int{200, 300},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := RouteAdd(&route); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
routes, err := RouteList(link, FAMILY_MPLS)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(routes) != 1 {
|
||||||
|
t.Fatal("Route not added properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := RouteDel(&route); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
routes, err = RouteList(link, FAMILY_MPLS)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(routes) != 0 {
|
||||||
|
t.Fatal("Route not removed properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
70
vendor/github.com/vishvananda/netlink/rule_test.go
generated
vendored
Normal file
70
vendor/github.com/vishvananda/netlink/rule_test.go
generated
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRuleAddDel(t *testing.T) {
|
||||||
|
skipUnlessRoot(t)
|
||||||
|
|
||||||
|
srcNet := &net.IPNet{IP: net.IPv4(172, 16, 0, 1), Mask: net.CIDRMask(16, 32)}
|
||||||
|
dstNet := &net.IPNet{IP: net.IPv4(172, 16, 1, 1), Mask: net.CIDRMask(24, 32)}
|
||||||
|
|
||||||
|
rulesBegin, err := RuleList(syscall.AF_INET)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rule := NewRule()
|
||||||
|
rule.Table = syscall.RT_TABLE_MAIN
|
||||||
|
rule.Src = srcNet
|
||||||
|
rule.Dst = dstNet
|
||||||
|
rule.Priority = 5
|
||||||
|
rule.OifName = "lo"
|
||||||
|
rule.IifName = "lo"
|
||||||
|
if err := RuleAdd(rule); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rules, err := RuleList(syscall.AF_INET)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rules) != len(rulesBegin)+1 {
|
||||||
|
t.Fatal("Rule not added properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
// find this rule
|
||||||
|
var found bool
|
||||||
|
for i := range rules {
|
||||||
|
if rules[i].Table == rule.Table &&
|
||||||
|
rules[i].Src != nil && rules[i].Src.String() == srcNet.String() &&
|
||||||
|
rules[i].Dst != nil && rules[i].Dst.String() == dstNet.String() &&
|
||||||
|
rules[i].OifName == rule.OifName &&
|
||||||
|
rules[i].Priority == rule.Priority &&
|
||||||
|
rules[i].IifName == rule.IifName {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Fatal("Rule has diffrent options than one added")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := RuleDel(rule); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rulesEnd, err := RuleList(syscall.AF_INET)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rulesEnd) != len(rulesBegin) {
|
||||||
|
t.Fatal("Rule not removed properly")
|
||||||
|
}
|
||||||
|
}
|
60
vendor/github.com/vishvananda/netlink/socket_test.go
generated
vendored
Normal file
60
vendor/github.com/vishvananda/netlink/socket_test.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/user"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSocketGet(t *testing.T) {
|
||||||
|
if os.Getenv("TRAVIS_BUILD_DIR") != "" {
|
||||||
|
t.Skipf("Goroutines + network namespaces == inconsistent results")
|
||||||
|
}
|
||||||
|
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
l, err := net.ListenTCP("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
conn, err := net.Dial(l.Addr().Network(), l.Addr().String())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
localAddr := conn.LocalAddr().(*net.TCPAddr)
|
||||||
|
remoteAddr := conn.RemoteAddr().(*net.TCPAddr)
|
||||||
|
socket, err := SocketGet(localAddr, remoteAddr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := socket.ID.Source, localAddr.IP; !got.Equal(want) {
|
||||||
|
t.Fatalf("local ip = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := socket.ID.Destination, remoteAddr.IP; !got.Equal(want) {
|
||||||
|
t.Fatalf("remote ip = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if got, want := int(socket.ID.SourcePort), localAddr.Port; got != want {
|
||||||
|
t.Fatalf("local port = %d, want %d", got, want)
|
||||||
|
}
|
||||||
|
if got, want := int(socket.ID.DestinationPort), remoteAddr.Port; got != want {
|
||||||
|
t.Fatalf("remote port = %d, want %d", got, want)
|
||||||
|
}
|
||||||
|
u, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if got, want := strconv.Itoa(int(socket.UID)), u.Uid; got != want {
|
||||||
|
t.Fatalf("UID = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
}
|
39
vendor/github.com/vishvananda/netlink/xfrm_monitor_test.go
generated
vendored
Normal file
39
vendor/github.com/vishvananda/netlink/xfrm_monitor_test.go
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/vishvananda/netlink/nl"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestXfrmMonitorExpire(t *testing.T) {
|
||||||
|
setUpNetlinkTest(t)()
|
||||||
|
|
||||||
|
ch := make(chan XfrmMsg)
|
||||||
|
done := make(chan struct{})
|
||||||
|
defer close(done)
|
||||||
|
errChan := make(chan error)
|
||||||
|
if err := XfrmMonitor(ch, nil, errChan, nl.XFRM_MSG_EXPIRE); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Program state with limits
|
||||||
|
state := getBaseState()
|
||||||
|
state.Limits.TimeHard = 2
|
||||||
|
state.Limits.TimeSoft = 1
|
||||||
|
if err := XfrmStateAdd(state); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := (<-ch).(*XfrmMsgExpire)
|
||||||
|
if msg.XfrmState.Spi != state.Spi || msg.Hard {
|
||||||
|
t.Fatal("Received unexpected msg")
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = (<-ch).(*XfrmMsgExpire)
|
||||||
|
if msg.XfrmState.Spi != state.Spi || !msg.Hard {
|
||||||
|
t.Fatal("Received unexpected msg")
|
||||||
|
}
|
||||||
|
}
|
199
vendor/github.com/vishvananda/netlink/xfrm_policy_test.go
generated
vendored
Normal file
199
vendor/github.com/vishvananda/netlink/xfrm_policy_test.go
generated
vendored
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
const zeroCIDR = "0.0.0.0/0"
|
||||||
|
|
||||||
|
func TestXfrmPolicyAddUpdateDel(t *testing.T) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
policy := getPolicy()
|
||||||
|
if err := XfrmPolicyAdd(policy); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
policies, err := XfrmPolicyList(FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(policies) != 1 {
|
||||||
|
t.Fatal("Policy not added properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !comparePolicies(policy, &policies[0]) {
|
||||||
|
t.Fatalf("unexpected policy returned.\nExpected: %v.\nGot %v", policy, policies[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for a specific policy
|
||||||
|
sp, err := XfrmPolicyGet(policy)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !comparePolicies(policy, sp) {
|
||||||
|
t.Fatalf("unexpected policy returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modify the policy
|
||||||
|
policy.Priority = 100
|
||||||
|
if err := XfrmPolicyUpdate(policy); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
sp, err = XfrmPolicyGet(policy)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if sp.Priority != 100 {
|
||||||
|
t.Fatalf("failed to modify the policy")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = XfrmPolicyDel(policy); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
policies, err = XfrmPolicyList(FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(policies) != 0 {
|
||||||
|
t.Fatal("Policy not removed properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Src and dst are not mandatory field. Creation should succeed
|
||||||
|
policy.Src = nil
|
||||||
|
policy.Dst = nil
|
||||||
|
if err = XfrmPolicyAdd(policy); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sp, err = XfrmPolicyGet(policy)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !comparePolicies(policy, sp) {
|
||||||
|
t.Fatalf("unexpected policy returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = XfrmPolicyDel(policy); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := XfrmPolicyGet(policy); err == nil {
|
||||||
|
t.Fatalf("Unexpected success")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmPolicyFlush(t *testing.T) {
|
||||||
|
setUpNetlinkTest(t)()
|
||||||
|
|
||||||
|
p1 := getPolicy()
|
||||||
|
if err := XfrmPolicyAdd(p1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p1.Dir = XFRM_DIR_IN
|
||||||
|
s := p1.Src
|
||||||
|
p1.Src = p1.Dst
|
||||||
|
p1.Dst = s
|
||||||
|
if err := XfrmPolicyAdd(p1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
policies, err := XfrmPolicyList(FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(policies) != 2 {
|
||||||
|
t.Fatalf("unexpected number of policies: %d", len(policies))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := XfrmPolicyFlush(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
policies, err = XfrmPolicyList(FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(policies) != 0 {
|
||||||
|
t.Fatalf("unexpected number of policies: %d", len(policies))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func comparePolicies(a, b *XfrmPolicy) bool {
|
||||||
|
if a == b {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if a == nil || b == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// Do not check Index which is assigned by kernel
|
||||||
|
return a.Dir == b.Dir && a.Priority == b.Priority &&
|
||||||
|
compareIPNet(a.Src, b.Src) && compareIPNet(a.Dst, b.Dst) &&
|
||||||
|
a.Mark.Value == b.Mark.Value && a.Mark.Mask == b.Mark.Mask &&
|
||||||
|
compareTemplates(a.Tmpls, b.Tmpls)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareTemplates(a, b []XfrmPolicyTmpl) bool {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i, ta := range a {
|
||||||
|
tb := b[i]
|
||||||
|
if !ta.Dst.Equal(tb.Dst) || !ta.Src.Equal(tb.Src) || ta.Spi != tb.Spi ||
|
||||||
|
ta.Mode != tb.Mode || ta.Reqid != tb.Reqid || ta.Proto != tb.Proto {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareIPNet(a, b *net.IPNet) bool {
|
||||||
|
if a == b {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// For unspecified src/dst parseXfrmPolicy would set the zero address cidr
|
||||||
|
if (a == nil && b.String() == zeroCIDR) || (b == nil && a.String() == zeroCIDR) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if a == nil || b == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPolicy() *XfrmPolicy {
|
||||||
|
src, _ := ParseIPNet("127.1.1.1/32")
|
||||||
|
dst, _ := ParseIPNet("127.1.1.2/32")
|
||||||
|
policy := &XfrmPolicy{
|
||||||
|
Src: src,
|
||||||
|
Dst: dst,
|
||||||
|
Proto: 17,
|
||||||
|
DstPort: 1234,
|
||||||
|
SrcPort: 5678,
|
||||||
|
Dir: XFRM_DIR_OUT,
|
||||||
|
Mark: &XfrmMark{
|
||||||
|
Value: 0xabff22,
|
||||||
|
Mask: 0xffffffff,
|
||||||
|
},
|
||||||
|
Priority: 10,
|
||||||
|
}
|
||||||
|
tmpl := XfrmPolicyTmpl{
|
||||||
|
Src: net.ParseIP("127.0.0.1"),
|
||||||
|
Dst: net.ParseIP("127.0.0.2"),
|
||||||
|
Proto: XFRM_PROTO_ESP,
|
||||||
|
Mode: XFRM_MODE_TUNNEL,
|
||||||
|
Spi: 0xabcdef99,
|
||||||
|
}
|
||||||
|
policy.Tmpls = append(policy.Tmpls, tmpl)
|
||||||
|
return policy
|
||||||
|
}
|
270
vendor/github.com/vishvananda/netlink/xfrm_state_test.go
generated
vendored
Normal file
270
vendor/github.com/vishvananda/netlink/xfrm_state_test.go
generated
vendored
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestXfrmStateAddGetDel(t *testing.T) {
|
||||||
|
for _, s := range []*XfrmState{getBaseState(), getAeadState()} {
|
||||||
|
testXfrmStateAddGetDel(t, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testXfrmStateAddGetDel(t *testing.T, state *XfrmState) {
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
if err := XfrmStateAdd(state); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
states, err := XfrmStateList(FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(states) != 1 {
|
||||||
|
t.Fatal("State not added properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !compareStates(state, &states[0]) {
|
||||||
|
t.Fatalf("unexpected states returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get specific state
|
||||||
|
sa, err := XfrmStateGet(state)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !compareStates(state, sa) {
|
||||||
|
t.Fatalf("unexpected state returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = XfrmStateDel(state); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
states, err = XfrmStateList(FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(states) != 0 {
|
||||||
|
t.Fatal("State not removed properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := XfrmStateGet(state); err == nil {
|
||||||
|
t.Fatalf("Unexpected success")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmStateAllocSpi(t *testing.T) {
|
||||||
|
setUpNetlinkTest(t)()
|
||||||
|
|
||||||
|
state := getBaseState()
|
||||||
|
state.Spi = 0
|
||||||
|
state.Auth = nil
|
||||||
|
state.Crypt = nil
|
||||||
|
rstate, err := XfrmStateAllocSpi(state)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if rstate.Spi == 0 {
|
||||||
|
t.Fatalf("SPI is not allocated")
|
||||||
|
}
|
||||||
|
rstate.Spi = 0
|
||||||
|
if !compareStates(state, rstate) {
|
||||||
|
t.Fatalf("State not properly allocated")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmStateFlush(t *testing.T) {
|
||||||
|
setUpNetlinkTest(t)()
|
||||||
|
|
||||||
|
state1 := getBaseState()
|
||||||
|
state2 := getBaseState()
|
||||||
|
state2.Src = net.ParseIP("127.1.0.1")
|
||||||
|
state2.Dst = net.ParseIP("127.1.0.2")
|
||||||
|
state2.Proto = XFRM_PROTO_AH
|
||||||
|
state2.Mode = XFRM_MODE_TUNNEL
|
||||||
|
state2.Spi = 20
|
||||||
|
state2.Mark = nil
|
||||||
|
state2.Crypt = nil
|
||||||
|
|
||||||
|
if err := XfrmStateAdd(state1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := XfrmStateAdd(state2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// flushing proto for which no state is present should return silently
|
||||||
|
if err := XfrmStateFlush(XFRM_PROTO_COMP); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := XfrmStateFlush(XFRM_PROTO_AH); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := XfrmStateGet(state2); err == nil {
|
||||||
|
t.Fatalf("Unexpected success")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := XfrmStateAdd(state2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := XfrmStateFlush(0); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
states, err := XfrmStateList(FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(states) != 0 {
|
||||||
|
t.Fatal("State not flushed properly")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXfrmStateUpdateLimits(t *testing.T) {
|
||||||
|
setUpNetlinkTest(t)()
|
||||||
|
|
||||||
|
// Program state with limits
|
||||||
|
state := getBaseState()
|
||||||
|
state.Limits.TimeHard = 3600
|
||||||
|
state.Limits.TimeSoft = 60
|
||||||
|
state.Limits.PacketHard = 1000
|
||||||
|
state.Limits.PacketSoft = 50
|
||||||
|
state.Limits.ByteHard = 1000000
|
||||||
|
state.Limits.ByteSoft = 50000
|
||||||
|
state.Limits.TimeUseHard = 3000
|
||||||
|
state.Limits.TimeUseSoft = 1500
|
||||||
|
if err := XfrmStateAdd(state); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// Verify limits
|
||||||
|
s, err := XfrmStateGet(state)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !compareLimits(state, s) {
|
||||||
|
t.Fatalf("Incorrect time hard/soft retrieved: %s", s.Print(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update limits
|
||||||
|
state.Limits.TimeHard = 1800
|
||||||
|
state.Limits.TimeSoft = 30
|
||||||
|
state.Limits.PacketHard = 500
|
||||||
|
state.Limits.PacketSoft = 25
|
||||||
|
state.Limits.ByteHard = 500000
|
||||||
|
state.Limits.ByteSoft = 25000
|
||||||
|
state.Limits.TimeUseHard = 2000
|
||||||
|
state.Limits.TimeUseSoft = 1000
|
||||||
|
if err := XfrmStateUpdate(state); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify new limits
|
||||||
|
s, err = XfrmStateGet(state)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if s.Limits.TimeHard != 1800 || s.Limits.TimeSoft != 30 {
|
||||||
|
t.Fatalf("Incorrect time hard retrieved: (%d, %d)", s.Limits.TimeHard, s.Limits.TimeSoft)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBaseState() *XfrmState {
|
||||||
|
return &XfrmState{
|
||||||
|
// Force 4 byte notation for the IPv4 addresses
|
||||||
|
Src: net.ParseIP("127.0.0.1").To4(),
|
||||||
|
Dst: net.ParseIP("127.0.0.2").To4(),
|
||||||
|
Proto: XFRM_PROTO_ESP,
|
||||||
|
Mode: XFRM_MODE_TUNNEL,
|
||||||
|
Spi: 1,
|
||||||
|
Auth: &XfrmStateAlgo{
|
||||||
|
Name: "hmac(sha256)",
|
||||||
|
Key: []byte("abcdefghijklmnopqrstuvwzyzABCDEF"),
|
||||||
|
},
|
||||||
|
Crypt: &XfrmStateAlgo{
|
||||||
|
Name: "cbc(aes)",
|
||||||
|
Key: []byte("abcdefghijklmnopqrstuvwzyzABCDEF"),
|
||||||
|
},
|
||||||
|
Mark: &XfrmMark{
|
||||||
|
Value: 0x12340000,
|
||||||
|
Mask: 0xffff0000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAeadState() *XfrmState {
|
||||||
|
// 128 key bits + 32 salt bits
|
||||||
|
k, _ := hex.DecodeString("d0562776bf0e75830ba3f7f8eb6c09b555aa1177")
|
||||||
|
return &XfrmState{
|
||||||
|
// Leave IPv4 addresses in Ipv4 in IPv6 notation
|
||||||
|
Src: net.ParseIP("192.168.1.1"),
|
||||||
|
Dst: net.ParseIP("192.168.2.2"),
|
||||||
|
Proto: XFRM_PROTO_ESP,
|
||||||
|
Mode: XFRM_MODE_TUNNEL,
|
||||||
|
Spi: 2,
|
||||||
|
Aead: &XfrmStateAlgo{
|
||||||
|
Name: "rfc4106(gcm(aes))",
|
||||||
|
Key: k,
|
||||||
|
ICVLen: 64,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareStates(a, b *XfrmState) bool {
|
||||||
|
if a == b {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if a == nil || b == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return a.Src.Equal(b.Src) && a.Dst.Equal(b.Dst) &&
|
||||||
|
a.Mode == b.Mode && a.Spi == b.Spi && a.Proto == b.Proto &&
|
||||||
|
compareAlgo(a.Auth, b.Auth) &&
|
||||||
|
compareAlgo(a.Crypt, b.Crypt) &&
|
||||||
|
compareAlgo(a.Aead, b.Aead) &&
|
||||||
|
compareMarks(a.Mark, b.Mark)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareLimits(a, b *XfrmState) bool {
|
||||||
|
return a.Limits.TimeHard == b.Limits.TimeHard &&
|
||||||
|
a.Limits.TimeSoft == b.Limits.TimeSoft &&
|
||||||
|
a.Limits.PacketHard == b.Limits.PacketHard &&
|
||||||
|
a.Limits.PacketSoft == b.Limits.PacketSoft &&
|
||||||
|
a.Limits.ByteHard == b.Limits.ByteHard &&
|
||||||
|
a.Limits.ByteSoft == b.Limits.ByteSoft &&
|
||||||
|
a.Limits.TimeUseHard == b.Limits.TimeUseHard &&
|
||||||
|
a.Limits.TimeUseSoft == b.Limits.TimeUseSoft
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareAlgo(a, b *XfrmStateAlgo) bool {
|
||||||
|
if a == b {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if a == nil || b == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return a.Name == b.Name && bytes.Equal(a.Key, b.Key) &&
|
||||||
|
(a.TruncateLen == 0 || a.TruncateLen == b.TruncateLen) &&
|
||||||
|
(a.ICVLen == 0 || a.ICVLen == b.ICVLen)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareMarks(a, b *XfrmMark) bool {
|
||||||
|
if a == b {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if a == nil || b == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return a.Value == b.Value && a.Mask == b.Mask
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user