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",
|
||||
"Rev": "fe3b5664d23a11b52ba59bece4ff29c52772a56b"
|
||||
"Rev": "b71e0bb214aebd980216cb2516e8bd7bca9e9672"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vishvananda/netlink/nl",
|
||||
"Rev": "fe3b5664d23a11b52ba59bece4ff29c52772a56b"
|
||||
"Rev": "b71e0bb214aebd980216cb2516e8bd7bca9e9672"
|
||||
},
|
||||
{
|
||||
"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
|
||||
# modprobe ip_gre or else the first gre device can't be deleted
|
||||
- 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:
|
||||
- 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.
|
||||
type Addr struct {
|
||||
*net.IPNet
|
||||
Label string
|
||||
Flags int
|
||||
Scope int
|
||||
Peer *net.IPNet
|
||||
Broadcast net.IP
|
||||
Label string
|
||||
Flags int
|
||||
Scope int
|
||||
Peer *net.IPNet
|
||||
Broadcast net.IP
|
||||
PreferedLft int
|
||||
ValidLft int
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Equivalent to: `ip addr del $addr dev $link`
|
||||
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])
|
||||
case IFA_FLAGS:
|
||||
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 {
|
||||
LinkAddress net.IPNet
|
||||
LinkIndex int
|
||||
Flags int
|
||||
Scope int
|
||||
PreferedLft int
|
||||
ValidLft int
|
||||
NewAddr bool // true=added false=deleted
|
||||
}
|
||||
|
||||
@ -250,7 +271,13 @@ func addrSubscribe(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-cha
|
||||
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
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
type Filter interface {
|
||||
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
|
||||
type U32 struct {
|
||||
FilterAttrs
|
||||
ClassId uint32
|
||||
RedirIndex int
|
||||
Sel *TcU32Sel
|
||||
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"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
@ -128,12 +129,34 @@ func (h *Handle) FilterAdd(filter Filter) error {
|
||||
|
||||
options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
|
||||
if u32, ok := filter.(*U32); ok {
|
||||
// match all
|
||||
sel := nl.TcU32Sel{
|
||||
Nkeys: 1,
|
||||
Flags: nl.TC_U32_TERMINAL,
|
||||
// Convert TcU32Sel into nl.TcU32Sel as it is without copy.
|
||||
sel := (*nl.TcU32Sel)(unsafe.Pointer(u32.Sel))
|
||||
if sel == nil {
|
||||
// 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())
|
||||
if u32.ClassId != 0 {
|
||||
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:
|
||||
detailed = true
|
||||
sel := nl.DeserializeTcU32Sel(datum.Value)
|
||||
// only parse if we have a very basic redirect
|
||||
if sel.Flags&nl.TC_U32_TERMINAL == 0 || sel.Nkeys != 1 {
|
||||
return detailed, nil
|
||||
u32.Sel = (*TcU32Sel)(unsafe.Pointer(sel))
|
||||
if native != networkOrder {
|
||||
// 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:
|
||||
tables, err := nl.ParseRouteAttr(datum.Value)
|
||||
@ -443,6 +472,8 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
|
||||
u32.RedirIndex = int(action.Ifindex)
|
||||
}
|
||||
}
|
||||
case nl.TCA_U32_CLASSID:
|
||||
u32.ClassId = native.Uint32(datum.Value)
|
||||
}
|
||||
}
|
||||
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 {
|
||||
base := link.Attrs()
|
||||
h.ensureIndex(base)
|
||||
@ -65,7 +103,7 @@ func (h *Handle) SetPromiscOn(link Link) error {
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Change = syscall.IFF_PROMISC
|
||||
msg.Flags = syscall.IFF_UP
|
||||
msg.Flags = syscall.IFF_PROMISC
|
||||
msg.Index = int32(base.Index)
|
||||
req.AddData(msg)
|
||||
|
||||
@ -84,7 +122,7 @@ func (h *Handle) SetPromiscOff(link Link) error {
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Change = syscall.IFF_PROMISC
|
||||
msg.Flags = 0 & ^syscall.IFF_UP
|
||||
msg.Flags = 0 & ^syscall.IFF_PROMISC
|
||||
msg.Index = int32(base.Index)
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
base := link.Attrs()
|
||||
h.ensureIndex(base)
|
||||
@ -1332,7 +1386,7 @@ func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
}
|
||||
|
||||
func parseBondData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
bond := NewLinkBond(NewLinkAttrs())
|
||||
bond := link.(*Bond)
|
||||
for i := range data {
|
||||
switch data[i].Attr.Type {
|
||||
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
|
||||
}
|
||||
|
||||
func LinkSetMaster(link Link, master *Link) error {
|
||||
func LinkSetMaster(link Link, master *Bridge) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
@ -64,6 +64,14 @@ func LinkSetXdpFd(link Link, fd int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetARPOff(link Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkSetARPOn(link Link) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func LinkByName(name string) (Link, error) {
|
||||
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 {
|
||||
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_LEARNING
|
||||
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 (
|
||||
|
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
|
||||
var SupportedNlFamilies = []int{syscall.NETLINK_ROUTE, syscall.NETLINK_XFRM}
|
||||
var SupportedNlFamilies = []int{syscall.NETLINK_ROUTE, syscall.NETLINK_XFRM, syscall.NETLINK_NETFILTER}
|
||||
|
||||
var nextSeqNr uint32
|
||||
|
||||
@ -321,6 +321,7 @@ func (a *RtAttr) Serialize() []byte {
|
||||
type NetlinkRequest struct {
|
||||
syscall.NlMsghdr
|
||||
Data []NetlinkRequestData
|
||||
RawData []byte
|
||||
Sockets map[int]*SocketHandle
|
||||
}
|
||||
|
||||
@ -332,6 +333,8 @@ func (req *NetlinkRequest) Serialize() []byte {
|
||||
dataBytes[i] = data.Serialize()
|
||||
length = length + len(dataBytes[i])
|
||||
}
|
||||
length += len(req.RawData)
|
||||
|
||||
req.Len = uint32(length)
|
||||
b := make([]byte, length)
|
||||
hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:]
|
||||
@ -343,6 +346,10 @@ func (req *NetlinkRequest) Serialize() []byte {
|
||||
next = next + 1
|
||||
}
|
||||
}
|
||||
// Add the raw data if any
|
||||
if len(req.RawData) > 0 {
|
||||
copy(b[next:length], req.RawData)
|
||||
}
|
||||
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.
|
||||
// Returns a list of netlink messages in serialized format, optionally filtered
|
||||
// by resType.
|
||||
@ -451,7 +465,7 @@ type NetlinkSocket struct {
|
||||
}
|
||||
|
||||
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 {
|
||||
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.
|
||||
type Protinfo struct {
|
||||
Hairpin bool
|
||||
Guard bool
|
||||
FastLeave bool
|
||||
RootBlock bool
|
||||
Learning bool
|
||||
Flood bool
|
||||
Hairpin bool
|
||||
Guard bool
|
||||
FastLeave bool
|
||||
RootBlock bool
|
||||
Learning bool
|
||||
Flood bool
|
||||
ProxyArp bool
|
||||
ProxyArpWiFi bool
|
||||
}
|
||||
|
||||
// String returns a list of enabled flags
|
||||
@ -35,6 +37,12 @@ func (prot *Protinfo) String() string {
|
||||
if prot.Flood {
|
||||
boolStrings = append(boolStrings, "Flood")
|
||||
}
|
||||
if prot.ProxyArp {
|
||||
boolStrings = append(boolStrings, "ProxyArp")
|
||||
}
|
||||
if prot.ProxyArpWiFi {
|
||||
boolStrings = append(boolStrings, "ProxyArpWiFi")
|
||||
}
|
||||
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])
|
||||
case nl.IFLA_BRPORT_UNICAST_FLOOD:
|
||||
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
|
||||
|
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