mirror of
https://github.com/vishvananda/netlink
synced 2025-02-27 10:01:00 +00:00
Make links have different types
This commit is contained in:
parent
2e7de143b9
commit
f87c54f846
@ -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
118
link.go
@ -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;
|
||||
|
162
link_linux.go
162
link_linux.go
@ -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]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
84
link_test.go
84
link_test.go
@ -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)
|
||||
}
|
||||
|
5
route.go
5
route.go
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user