Make links have different types

This commit is contained in:
Vishvananda Ishaya 2014-09-23 22:21:11 -07:00
parent 2e7de143b9
commit f87c54f846
6 changed files with 289 additions and 124 deletions

View File

@ -5,13 +5,13 @@ import (
"net"
"strings"
"syscall"
"github.com/vishvananda/netlink/nl"
)
// AddrAdd will add an IP address to a link device.
// Equivalent to: `ip addr del $addr dev $link`
func AddrAdd(link *Link, addr *Addr) error {
func AddrAdd(link Link, addr *Addr) error {
req := nl.NewNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
return addrHandle(link, addr, req)
@ -19,21 +19,22 @@ func AddrAdd(link *Link, addr *Addr) error {
// 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 {
func AddrDel(link Link, addr *Addr) error {
req := nl.NewNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK)
return addrHandle(link, addr, req)
}
func addrHandle(link *Link, addr *Addr, req *nl.NetlinkRequest) error {
if addr.Label != "" && !strings.HasPrefix(addr.Label, link.Name) {
func addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error {
base := link.Attrs()
if addr.Label != "" && !strings.HasPrefix(addr.Label, base.Name) {
return fmt.Errorf("label must begin with interface name")
}
ensureIndex(link)
ensureIndex(base)
family := nl.GetIPFamily(addr.IP)
msg := nl.NewIfAddrmsg(family)
msg.Index = uint32(link.Index)
msg.Index = uint32(base.Index)
prefixlen, _ := addr.Mask.Size()
msg.Prefixlen = uint8(prefixlen)
req.AddData(msg)
@ -63,7 +64,7 @@ func addrHandle(link *Link, addr *Addr, req *nl.NetlinkRequest) error {
// AddrList gets a list of IP addresses in the system.
// Equivalent to: `ip addr show`.
// The list can be filtered by link and ip family.
func AddrList(link *Link, family int) ([]Addr, error) {
func AddrList(link Link, family int) ([]Addr, error) {
req := nl.NewNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
msg := nl.NewIfInfomsg(family)
req.AddData(msg)
@ -73,13 +74,18 @@ func AddrList(link *Link, family int) ([]Addr, error) {
return nil, err
}
ensureIndex(link)
index := 0
if link != nil {
base := link.Attrs()
ensureIndex(base)
index = base.Index
}
res := make([]Addr, 0)
for _, m := range msgs {
msg := nl.DeserializeIfAddrmsg(m)
if link != nil && msg.Index != uint32(link.Index) {
if link != nil && msg.Index != uint32(index) {
// Ignore messages from other interfaces
continue
}

118
link.go
View File

@ -4,21 +4,119 @@ import (
"net"
)
// Link represents a link device from netlink. The Type is a string
// representing the type of device. Currently supported types include:
// "dummy", "bridge", "vlan", "macvlan", and "veth". Some of the
// members of Link only apply to some types of link devices.
type Link struct {
Type string
// Link represents a link device from netlink. Shared link attributes
// like name may be retrieved using the Attrs() method. Unique data
// can be retrieved by casting the object to the proper type.
type Link interface {
Attrs() *LinkAttrs
Type() string
}
// LinkAttrs represents data shared by most link types
type LinkAttrs struct {
Index int
MTU int
Name string
HardwareAddr net.HardwareAddr
Flags net.Flags
Parent *Link // vlan and macvlan
Master *Link // bridge only
VlanId int // vlan only
PeerName string // veth on create only
ParentIndex int // index of the parent link device
MasterIndex int // must be the index of a bridge
}
// Device links cannot be created via netlink. These links
// are links created by udev like 'lo' and 'etho0'
type Device struct {
LinkAttrs
}
func (device *Device) Attrs() *LinkAttrs {
return &device.LinkAttrs
}
func (device *Device) Type() string {
return "device"
}
// Dummy links are dummy ethernet devices
type Dummy struct {
LinkAttrs
}
func (dummy *Dummy) Attrs() *LinkAttrs {
return &dummy.LinkAttrs
}
func (dummy *Dummy) Type() string {
return "dummy"
}
// Bridge links are simple linux bridges
type Bridge struct {
LinkAttrs
}
func (bridge *Bridge) Attrs() *LinkAttrs {
return &bridge.LinkAttrs
}
func (bridge *Bridge) Type() string {
return "bridge"
}
// Vlan links have ParentIndex set in their Attrs()
type Vlan struct {
LinkAttrs
VlanId int
}
func (vlan *Vlan) Attrs() *LinkAttrs {
return &vlan.LinkAttrs
}
func (vlan *Vlan) Type() string {
return "vlan"
}
// Macvlan links have ParentIndex set in their Attrs()
type Macvlan struct {
LinkAttrs
}
func (macvlan *Macvlan) Attrs() *LinkAttrs {
return &macvlan.LinkAttrs
}
func (macvlan *Macvlan) Type() string {
return "macvlan"
}
// Veth devices must specify PeerName on create
type Veth struct {
LinkAttrs
PeerName string // veth on create only
}
func (veth *Veth) Attrs() *LinkAttrs {
return &veth.LinkAttrs
}
func (veth *Veth) Type() string {
return "veth"
}
// Generic links represent types that are not currently understood
// by this netlink library.
type Generic struct {
LinkAttrs
LinkType string
}
func (generic *Generic) Attrs() *LinkAttrs {
return &generic.LinkAttrs
}
func (generic *Generic) Type() string {
return generic.LinkType
}
// iproute2 supported devices;

View File

@ -9,25 +9,26 @@ import (
"github.com/vishvananda/netlink/nl"
)
func ensureIndex(link *Link) {
func ensureIndex(link *LinkAttrs) {
if link != nil && link.Index == 0 {
newlink, _ := LinkByName(link.Name)
if newlink != nil {
link.Index = newlink.Index
link.Index = newlink.Attrs().Index
}
}
}
// LinkSetUp enables the link device.
// Equivalent to: `ip link set $link up`
func LinkSetUp(link *Link) error {
ensureIndex(link)
func LinkSetUp(link Link) error {
base := link.Attrs()
ensureIndex(base)
req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Change = syscall.IFF_UP
msg.Flags = syscall.IFF_UP
msg.Index = int32(link.Index)
msg.Index = int32(base.Index)
req.AddData(msg)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
@ -36,14 +37,15 @@ func LinkSetUp(link *Link) error {
// LinkSetUp disables link device.
// Equivalent to: `ip link set $link down`
func LinkSetDown(link *Link) error {
ensureIndex(link)
func LinkSetDown(link Link) error {
base := link.Attrs()
ensureIndex(base)
req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Change = syscall.IFF_UP
msg.Flags = 0 & ^syscall.IFF_UP
msg.Index = int32(link.Index)
msg.Index = int32(base.Index)
req.AddData(msg)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
@ -52,14 +54,15 @@ func LinkSetDown(link *Link) error {
// LinkSetMTU sets the mtu of the link device.
// Equivalent to: `ip link set $link mtu $mtu`
func LinkSetMTU(link *Link, mtu int) error {
ensureIndex(link)
func LinkSetMTU(link Link, mtu int) error {
base := link.Attrs()
ensureIndex(base)
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Type = syscall.RTM_SETLINK
msg.Flags = syscall.NLM_F_REQUEST
msg.Index = int32(link.Index)
msg.Index = int32(base.Index)
msg.Change = nl.DEFAULT_CHANGE
req.AddData(msg)
@ -76,32 +79,38 @@ func LinkSetMTU(link *Link, mtu int) error {
return err
}
// LinkSetMTU sets the master of the link device. This only works
// for bridges.
// LinkSetMaster sets the master of the link device.
// Equivalent to: `ip link set $link master $master`
func LinkSetMaster(link *Link, master *Link) error {
ensureIndex(link)
ensureIndex(master)
func LinkSetMaster(link Link, master *Bridge) error {
index := 0
if master != nil {
masterBase := master.Attrs()
ensureIndex(masterBase)
index = masterBase.Index
}
return LinkSetMasterByIndex(link, index)
}
// LinkSetMasterByIndex sets the master of the link device.
// Equivalent to: `ip link set $link master $master`
func LinkSetMasterByIndex(link Link, masterIndex int) error {
base := link.Attrs()
ensureIndex(base)
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Type = syscall.RTM_SETLINK
msg.Flags = syscall.NLM_F_REQUEST
msg.Index = int32(link.Index)
msg.Index = int32(base.Index)
msg.Change = nl.DEFAULT_CHANGE
req.AddData(msg)
var (
b = make([]byte, 4)
native = nl.NativeEndian()
index = 0
)
if master != nil {
index = master.Index
}
native.PutUint32(b, uint32(index))
native.PutUint32(b, uint32(masterIndex))
data := nl.NewRtAttr(syscall.IFLA_MASTER, b)
req.AddData(data)
@ -113,13 +122,15 @@ func LinkSetMaster(link *Link, master *Link) error {
// LinkSetNsPid puts the device into a new network namespace. The
// pid must be a pid of a running process.
// Equivalent to: `ip link set $link netns $pid`
func LinkSetNsPid(link *Link, nspid int) error {
func LinkSetNsPid(link Link, nspid int) error {
base := link.Attrs()
ensureIndex(base)
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Type = syscall.RTM_SETLINK
msg.Flags = syscall.NLM_F_REQUEST
msg.Index = int32(link.Index)
msg.Index = int32(base.Index)
msg.Change = nl.DEFAULT_CHANGE
req.AddData(msg)
@ -139,13 +150,15 @@ func LinkSetNsPid(link *Link, nspid int) error {
// LinkSetNsPid puts the device into a new network namespace. The
// fd must be an open file descriptor to a network namespace.
// Similar to: `ip link set $link netns $ns`
func LinkSetNsFd(link *Link, fd int) error {
func LinkSetNsFd(link Link, fd int) error {
base := link.Attrs()
ensureIndex(base)
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Type = syscall.RTM_SETLINK
msg.Flags = syscall.NLM_F_REQUEST
msg.Index = int32(link.Index)
msg.Index = int32(base.Index)
msg.Change = nl.DEFAULT_CHANGE
req.AddData(msg)
@ -165,12 +178,13 @@ func LinkSetNsFd(link *Link, fd int) error {
// LinkAdd adds a new link device. The type and features of the device
// are taken fromt the parameters in the link object.
// Equivalent to: `ip link add $link`
func LinkAdd(link *Link) error {
func LinkAdd(link Link) error {
// TODO: set mtu and hardware address
// TODO: support extra data for macvlan
base := link.Attrs()
if link.Type == "" || link.Name == "" {
return fmt.Errorf("Neither link.Name nor link.Type can be empty!")
if base.Name == "" {
return fmt.Errorf("LinkAttrs.Name cannot be empty!")
}
req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
@ -180,30 +194,29 @@ func LinkAdd(link *Link) error {
native := nl.NativeEndian()
if link.Parent != nil {
ensureIndex(link.Parent)
if base.ParentIndex != 0 {
b := make([]byte, 4)
native.PutUint32(b, uint32(link.Parent.Index))
native.PutUint32(b, uint32(base.ParentIndex))
data := nl.NewRtAttr(syscall.IFLA_LINK, b)
req.AddData(data)
}
nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(link.Name))
nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(base.Name))
req.AddData(nameData)
linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil)
nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type))
nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
if link.Type == "vlan" {
if vlan, ok := link.(*Vlan); ok {
b := make([]byte, 2)
native.PutUint16(b, uint16(link.VlanId))
native.PutUint16(b, uint16(vlan.VlanId))
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
nl.NewRtAttrChild(data, nl.IFLA_VLAN_ID, b)
} else if link.Type == "veth" {
} else if veth, ok := link.(*Veth); ok {
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
peer := nl.NewRtAttrChild(data, nl.VETH_INFO_PEER, nil)
nl.NewIfInfomsgChild(peer, syscall.AF_UNSPEC)
nl.NewRtAttrChild(peer, syscall.IFLA_IFNAME, nl.ZeroTerminated(link.PeerName))
nl.NewRtAttrChild(peer, syscall.IFLA_IFNAME, nl.ZeroTerminated(veth.PeerName))
}
req.AddData(linkInfo)
@ -213,9 +226,12 @@ func LinkAdd(link *Link) error {
return err
}
ensureIndex(base)
// can't set master during create, so set it afterwards
if link.Master != nil {
return LinkSetMaster(link, link.Master)
if base.MasterIndex != 0 {
// TODO: verify MasterIndex is actually a bridge?
return LinkSetMasterByIndex(link, base.MasterIndex)
}
return nil
}
@ -223,13 +239,15 @@ func LinkAdd(link *Link) error {
// LinkAdd adds a new link device. Either Index or Name must be set in
// the link object for it to be deleted. The other values are ignored.
// Equivalent to: `ip link del $link`
func LinkDel(link *Link) error {
ensureIndex(link)
func LinkDel(link Link) error {
base := link.Attrs()
ensureIndex(base)
req := nl.NewNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Index = int32(link.Index)
msg.Index = int32(base.Index)
req.AddData(msg)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
@ -237,28 +255,30 @@ func LinkDel(link *Link) error {
}
// LikByName finds a link by name and returns a pointer to the object.
func LinkByName(name string) (*Link, error) {
func LinkByName(name string) (Link, error) {
links, err := LinkList()
if err != nil {
return nil, err
}
for _, link := range links {
if link.Name == name {
return &link, nil
base := link.Attrs()
if base.Name == name {
return link, nil
}
}
return nil, fmt.Errorf("Link %s not found", name)
}
// LikByName finds a link by index and returns a pointer to the object.
func LinkByIndex(index int) (*Link, error) {
func LinkByIndex(index int) (Link, error) {
links, err := LinkList()
if err != nil {
return nil, err
}
for _, link := range links {
if link.Index == index {
return &link, nil
base := link.Attrs()
if base.Index == index {
return link, nil
}
}
return nil, fmt.Errorf("Link with index %d not found", index)
@ -290,7 +310,9 @@ func LinkList() ([]Link, error) {
return nil, err
}
link := Link{Index: int(msg.Index), Flags: linkFlags(msg.Flags)}
base := LinkAttrs{Index: int(msg.Index), Flags: linkFlags(msg.Flags)}
var link Link
linkType := ""
for _, attr := range attrs {
switch attr.Attr.Type {
case syscall.IFLA_LINKINFO:
@ -301,15 +323,27 @@ func LinkList() ([]Link, error) {
for _, info := range infos {
switch info.Attr.Type {
case nl.IFLA_INFO_KIND:
link.Type = string(info.Value[:len(info.Value)-1])
linkType = string(info.Value[:len(info.Value)-1])
switch linkType {
case "dummy":
link = &Dummy{}
case "bridge":
link = &Bridge{}
case "vlan":
link = &Vlan{}
case "veth":
link = &Veth{}
default:
link = &Generic{LinkType: linkType}
}
case nl.IFLA_INFO_DATA:
data, err := nl.ParseRouteAttr(info.Value)
if err != nil {
return nil, err
}
switch link.Type {
switch linkType {
case "vlan":
parseVlanData(&link, data, native)
parseVlanData(link, data, native)
}
}
}
@ -321,29 +355,35 @@ func LinkList() ([]Link, error) {
}
}
if nonzero {
link.HardwareAddr = attr.Value[:]
base.HardwareAddr = attr.Value[:]
}
case syscall.IFLA_IFNAME:
link.Name = string(attr.Value[:len(attr.Value)-1])
base.Name = string(attr.Value[:len(attr.Value)-1])
case syscall.IFLA_MTU:
link.MTU = int(native.Uint32(attr.Value[0:4]))
base.MTU = int(native.Uint32(attr.Value[0:4]))
case syscall.IFLA_LINK:
link.Parent = &Link{Index: int(native.Uint32(attr.Value[0:4]))}
base.ParentIndex = int(native.Uint32(attr.Value[0:4]))
case syscall.IFLA_MASTER:
link.Master = &Link{Index: int(native.Uint32(attr.Value[0:4]))}
base.MasterIndex = int(native.Uint32(attr.Value[0:4]))
}
}
// Links that don't have IFLA_INFO_KIND are hardware devices
if link == nil {
link = &Device{}
}
*link.Attrs() = base
res = append(res, link)
}
return res, nil
}
func parseVlanData(link *Link, data []syscall.NetlinkRouteAttr, native binary.ByteOrder) {
func parseVlanData(link Link, data []syscall.NetlinkRouteAttr, native binary.ByteOrder) {
vlan, _ := link.(*Vlan)
for _, datum := range data {
switch datum.Attr.Type {
case nl.IFLA_VLAN_ID:
link.VlanId = int(native.Uint16(datum.Value[0:2]))
vlan.VlanId = int(native.Uint16(datum.Value[0:2]))
}
}
}

View File

@ -5,7 +5,7 @@ import (
"testing"
)
func testLinkAddDel(t *testing.T, link *Link) {
func testLinkAddDel(t *testing.T, link Link) {
links, err := LinkList()
if err != nil {
t.Fatal(err)
@ -16,34 +16,44 @@ func testLinkAddDel(t *testing.T, link *Link) {
t.Fatal(err)
}
l, err := LinkByName(link.Name)
base := link.Attrs()
result, err := LinkByName(base.Name)
if err != nil {
t.Fatal(err)
}
if l.Type != link.Type {
t.Fatal("Link.Type doesn't match")
}
rBase := result.Attrs()
if l.VlanId != link.VlanId {
t.Fatal("Link.VlanId id doesn't match")
}
if l.Parent == nil && link.Parent != nil {
t.Fatal("Created link doesn't have a Parent but it should")
} else if l.Parent != nil && link.Parent == nil {
t.Fatal("Created link has a Parent but it shouldn't")
} else if l.Parent != nil && link.Parent != nil {
if l.Parent.Index != link.Parent.Index {
t.Fatal("Link.Parent.Index doesn't match")
if vlan, ok := link.(*Vlan); ok {
other, ok := result.(*Vlan)
if !ok {
t.Fatal("Result of create is not a vlan")
}
if vlan.VlanId != other.VlanId {
t.Fatal("Link.VlanId id doesn't match")
}
}
if link.PeerName != "" {
_, err := LinkByName(link.PeerName)
if err != nil {
t.Fatal("Peer %s not created", link.PeerName)
if rBase.ParentIndex == 0 && base.ParentIndex != 0 {
t.Fatal("Created link doesn't have a Parent but it should")
} else if rBase.ParentIndex != 0 && base.ParentIndex == 0 {
t.Fatal("Created link has a Parent but it shouldn't")
} else if rBase.ParentIndex != 0 && base.ParentIndex != 0 {
if rBase.ParentIndex != base.ParentIndex {
t.Fatal("Link.ParentIndex doesn't match")
}
}
if veth, ok := link.(*Veth); ok {
if veth.PeerName != "" {
other, err := LinkByName(veth.PeerName)
if err != nil {
t.Fatal("Peer %s not created", veth.PeerName)
}
if _, ok = other.(*Veth); !ok {
t.Fatal("Peer %s is incorrect type", veth.PeerName)
}
}
}
@ -65,25 +75,26 @@ func TestLinkAddDelDummy(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
testLinkAddDel(t, &Link{Name: "foo", Type: "dummy"})
testLinkAddDel(t, &Dummy{LinkAttrs{Name: "foo"}})
}
func TestLinkAddDelBridge(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
testLinkAddDel(t, &Link{Name: "foo", Type: "bridge"})
testLinkAddDel(t, &Bridge{LinkAttrs{Name: "foo"}})
}
func TestLinkAddDelVlan(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
parent := &Link{Name: "foo", Type: "dummy"}
parent := &Dummy{LinkAttrs{Name: "foo"}}
if err := LinkAdd(parent); err != nil {
t.Fatal(err)
}
testLinkAddDel(t, &Link{Name: "bar", Type: "vlan", Parent: parent, VlanId: 900})
testLinkAddDel(t, &Vlan{LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index}, 900})
if err := LinkDel(parent); err != nil {
t.Fatal(err)
@ -94,11 +105,12 @@ func TestLinkAddDelMacvlan(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
parent := &Link{Name: "foo", Type: "dummy"}
parent := &Dummy{LinkAttrs{Name: "foo"}}
if err := LinkAdd(parent); err != nil {
t.Fatal(err)
}
testLinkAddDel(t, &Link{Name: "bar", Type: "macvlan", Parent: parent})
testLinkAddDel(t, &Macvlan{LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index}})
if err := LinkDel(parent); err != nil {
t.Fatal(err)
@ -109,18 +121,18 @@ func TestLinkAddDelVeth(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
testLinkAddDel(t, &Link{Name: "foo", Type: "veth", PeerName: "bar"})
testLinkAddDel(t, &Veth{LinkAttrs{Name: "foo"}, "bar"})
}
func TestLinkAddDelBridgeMaster(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
master := &Link{Name: "foo", Type: "bridge"}
master := &Bridge{LinkAttrs{Name: "foo"}}
if err := LinkAdd(master); err != nil {
t.Fatal(err)
}
testLinkAddDel(t, &Link{Name: "bar", Type: "dummy", Master: master})
testLinkAddDel(t, &Dummy{LinkAttrs{Name: "bar", MasterIndex: master.Attrs().Index}})
if err := LinkDel(master); err != nil {
t.Fatal(err)
@ -131,17 +143,17 @@ func TestLinkSetUnsetResetMaster(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
master := &Link{Name: "foo", Type: "bridge"}
master := &Bridge{LinkAttrs{Name: "foo"}}
if err := LinkAdd(master); err != nil {
t.Fatal(err)
}
newmaster := &Link{Name: "bar", Type: "bridge"}
newmaster := &Bridge{LinkAttrs{Name: "bar"}}
if err := LinkAdd(newmaster); err != nil {
t.Fatal(err)
}
slave := &Link{Name: "baz", Type: "dummy"}
slave := &Dummy{LinkAttrs{Name: "baz"}}
if err := LinkAdd(slave); err != nil {
t.Fatal(err)
}
@ -155,7 +167,7 @@ func TestLinkSetUnsetResetMaster(t *testing.T) {
t.Fatal(err)
}
if link.Master == nil || link.Master.Index != master.Index {
if link.Attrs().MasterIndex != master.Attrs().Index {
t.Fatal("Master not set properly")
}
@ -168,7 +180,7 @@ func TestLinkSetUnsetResetMaster(t *testing.T) {
t.Fatal(err)
}
if link.Master == nil || link.Master.Index != newmaster.Index {
if link.Attrs().MasterIndex != newmaster.Attrs().Index {
t.Fatal("Master not reset properly")
}
@ -181,7 +193,7 @@ func TestLinkSetUnsetResetMaster(t *testing.T) {
t.Fatal(err)
}
if link.Master != nil {
if link.Attrs().MasterIndex != 0 {
t.Fatal("Master not unset properly")
}
if err := LinkDel(slave); err != nil {
@ -213,7 +225,7 @@ func TestLinkSetNs(t *testing.T) {
}
defer newns.Close()
link := &Link{Name: "foo", Type: "veth", PeerName: "bar"}
link := &Veth{LinkAttrs{Name: "foo"}, "bar"}
if err := LinkAdd(link); err != nil {
t.Fatal(err)
}

View File

@ -22,7 +22,7 @@ const (
// gateway. Advanced route parameters and non-main routing tables are
// currently not supported.
type Route struct {
Link *Link
Link Link
Scope Scope
Dst *net.IPNet
Src net.IP
@ -30,6 +30,7 @@ type Route struct {
}
func (r Route) String() string {
return fmt.Sprintf("{%s Dst: %s Src: %s Gw: %s}", r.Link.Name, r.Dst.String(),
base := r.Link.Attrs()
return fmt.Sprintf("{%s Dst: %s Src: %s Gw: %s}", base.Name, r.Dst.String(),
r.Src, r.Gw)
}

View File

@ -90,7 +90,8 @@ func routeHandle(route *Route, req *nl.NetlinkRequest) error {
b = make([]byte, 4)
native = nl.NativeEndian()
)
native.PutUint32(b, uint32(route.Link.Index))
base := route.Link.Attrs()
native.PutUint32(b, uint32(base.Index))
req.AddData(nl.NewRtAttr(syscall.RTA_OIF, b))
@ -101,7 +102,7 @@ func routeHandle(route *Route, req *nl.NetlinkRequest) error {
// RouteList gets a list of routes in the system.
// Equivalent to: `ip route show`.
// The list can be filtered by link and ip family.
func RouteList(link *Link, family int) ([]Route, error) {
func RouteList(link Link, family int) ([]Route, error) {
req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP)
msg := nl.NewIfInfomsg(family)
req.AddData(msg)
@ -111,6 +112,13 @@ func RouteList(link *Link, family int) ([]Route, error) {
return nil, err
}
index := 0
if link != nil {
base := link.Attrs()
ensureIndex(base)
index = base.Index
}
native := nl.NativeEndian()
res := make([]Route, 0)
for _, m := range msgs {
@ -144,12 +152,12 @@ func RouteList(link *Link, family int) ([]Route, error) {
Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)),
}
case syscall.RTA_OIF:
index := int(native.Uint32(attr.Value[0:4]))
if link != nil && index != link.Index {
routeIndex := int(native.Uint32(attr.Value[0:4]))
if link != nil && routeIndex != index {
// Ignore routes from other interfaces
continue
}
resLink, _ := LinkByIndex(index)
resLink, _ := LinkByIndex(routeIndex)
route.Link = resLink
}
}