mirror of
https://github.com/vishvananda/netlink
synced 2025-04-10 11:31:47 +00:00
avoid dumping all interfaces to look up one
This commit is contained in:
parent
e7911d879f
commit
cc912bac14
231
link_linux.go
231
link_linux.go
@ -10,6 +10,8 @@ import (
|
|||||||
"github.com/vishvananda/netlink/nl"
|
"github.com/vishvananda/netlink/nl"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var native = nl.NativeEndian()
|
||||||
|
|
||||||
func ensureIndex(link *LinkAttrs) {
|
func ensureIndex(link *LinkAttrs) {
|
||||||
if link != nil && link.Index == 0 {
|
if link != nil && link.Index == 0 {
|
||||||
newlink, _ := LinkByName(link.Name)
|
newlink, _ := LinkByName(link.Name)
|
||||||
@ -67,10 +69,7 @@ func LinkSetMTU(link Link, mtu int) error {
|
|||||||
msg.Change = nl.DEFAULT_CHANGE
|
msg.Change = nl.DEFAULT_CHANGE
|
||||||
req.AddData(msg)
|
req.AddData(msg)
|
||||||
|
|
||||||
var (
|
b := make([]byte, 4)
|
||||||
b = make([]byte, 4)
|
|
||||||
native = nl.NativeEndian()
|
|
||||||
)
|
|
||||||
native.PutUint32(b, uint32(mtu))
|
native.PutUint32(b, uint32(mtu))
|
||||||
|
|
||||||
data := nl.NewRtAttr(syscall.IFLA_MTU, b)
|
data := nl.NewRtAttr(syscall.IFLA_MTU, b)
|
||||||
@ -106,11 +105,7 @@ func LinkSetMasterByIndex(link Link, masterIndex int) error {
|
|||||||
msg.Change = nl.DEFAULT_CHANGE
|
msg.Change = nl.DEFAULT_CHANGE
|
||||||
req.AddData(msg)
|
req.AddData(msg)
|
||||||
|
|
||||||
var (
|
b := make([]byte, 4)
|
||||||
b = make([]byte, 4)
|
|
||||||
native = nl.NativeEndian()
|
|
||||||
)
|
|
||||||
|
|
||||||
native.PutUint32(b, uint32(masterIndex))
|
native.PutUint32(b, uint32(masterIndex))
|
||||||
|
|
||||||
data := nl.NewRtAttr(syscall.IFLA_MASTER, b)
|
data := nl.NewRtAttr(syscall.IFLA_MASTER, b)
|
||||||
@ -135,10 +130,7 @@ func LinkSetNsPid(link Link, nspid int) error {
|
|||||||
msg.Change = nl.DEFAULT_CHANGE
|
msg.Change = nl.DEFAULT_CHANGE
|
||||||
req.AddData(msg)
|
req.AddData(msg)
|
||||||
|
|
||||||
var (
|
b := make([]byte, 4)
|
||||||
b = make([]byte, 4)
|
|
||||||
native = nl.NativeEndian()
|
|
||||||
)
|
|
||||||
native.PutUint32(b, uint32(nspid))
|
native.PutUint32(b, uint32(nspid))
|
||||||
|
|
||||||
data := nl.NewRtAttr(syscall.IFLA_NET_NS_PID, b)
|
data := nl.NewRtAttr(syscall.IFLA_NET_NS_PID, b)
|
||||||
@ -163,10 +155,7 @@ func LinkSetNsFd(link Link, fd int) error {
|
|||||||
msg.Change = nl.DEFAULT_CHANGE
|
msg.Change = nl.DEFAULT_CHANGE
|
||||||
req.AddData(msg)
|
req.AddData(msg)
|
||||||
|
|
||||||
var (
|
b := make([]byte, 4)
|
||||||
b = make([]byte, 4)
|
|
||||||
native = nl.NativeEndian()
|
|
||||||
)
|
|
||||||
native.PutUint32(b, uint32(fd))
|
native.PutUint32(b, uint32(fd))
|
||||||
|
|
||||||
data := nl.NewRtAttr(nl.IFLA_NET_NS_FD, b)
|
data := nl.NewRtAttr(nl.IFLA_NET_NS_FD, b)
|
||||||
@ -263,8 +252,6 @@ func LinkAdd(link Link) error {
|
|||||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||||
req.AddData(msg)
|
req.AddData(msg)
|
||||||
|
|
||||||
native := nl.NativeEndian()
|
|
||||||
|
|
||||||
if base.ParentIndex != 0 {
|
if base.ParentIndex != 0 {
|
||||||
b := make([]byte, 4)
|
b := make([]byte, 4)
|
||||||
native.PutUint32(b, uint32(base.ParentIndex))
|
native.PutUint32(b, uint32(base.ParentIndex))
|
||||||
@ -329,32 +316,128 @@ func LinkDel(link Link) error {
|
|||||||
|
|
||||||
// LikByName finds a link by name and returns a pointer to the object.
|
// 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()
|
req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||||
}
|
req.AddData(msg)
|
||||||
for _, link := range links {
|
|
||||||
base := link.Attrs()
|
nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(name))
|
||||||
if base.Name == name {
|
req.AddData(nameData)
|
||||||
return link, nil
|
|
||||||
}
|
return execGetLink(req)
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("Link %s not found", name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LikByName finds a link by index and returns a pointer to the object.
|
// 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()
|
req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK)
|
||||||
|
|
||||||
|
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||||
|
msg.Index = int32(index)
|
||||||
|
req.AddData(msg)
|
||||||
|
|
||||||
|
return execGetLink(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func execGetLink(req *nl.NetlinkRequest) (Link, error) {
|
||||||
|
msgs, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
||||||
|
if err != nil {
|
||||||
|
if errno, ok := err.(syscall.Errno); ok {
|
||||||
|
if errno == syscall.ENODEV {
|
||||||
|
return nil, fmt.Errorf("Link not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case len(msgs) == 0:
|
||||||
|
return nil, fmt.Errorf("Link not found")
|
||||||
|
|
||||||
|
case len(msgs) == 1:
|
||||||
|
return LinkDeserialize(msgs[0])
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("More than one link found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize raw message received from netlink into link object.
|
||||||
|
func LinkDeserialize(m []byte) (Link, error) {
|
||||||
|
msg := nl.DeserializeIfInfomsg(m)
|
||||||
|
|
||||||
|
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, link := range links {
|
|
||||||
base := link.Attrs()
|
base := LinkAttrs{Index: int(msg.Index), Flags: linkFlags(msg.Flags)}
|
||||||
if base.Index == index {
|
var link Link
|
||||||
return link, nil
|
linkType := ""
|
||||||
|
for _, attr := range attrs {
|
||||||
|
switch attr.Attr.Type {
|
||||||
|
case syscall.IFLA_LINKINFO:
|
||||||
|
infos, err := nl.ParseRouteAttr(attr.Value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, info := range infos {
|
||||||
|
switch info.Attr.Type {
|
||||||
|
case nl.IFLA_INFO_KIND:
|
||||||
|
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{}
|
||||||
|
case "vxlan":
|
||||||
|
link = &Vxlan{}
|
||||||
|
default:
|
||||||
|
link = &Generic{LinkType: linkType}
|
||||||
|
}
|
||||||
|
case nl.IFLA_INFO_DATA:
|
||||||
|
data, err := nl.ParseRouteAttr(info.Value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch linkType {
|
||||||
|
case "vlan":
|
||||||
|
parseVlanData(link, data)
|
||||||
|
case "vxlan":
|
||||||
|
parseVxlanData(link, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case syscall.IFLA_ADDRESS:
|
||||||
|
var nonzero bool
|
||||||
|
for _, b := range attr.Value {
|
||||||
|
if b != 0 {
|
||||||
|
nonzero = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if nonzero {
|
||||||
|
base.HardwareAddr = attr.Value[:]
|
||||||
|
}
|
||||||
|
case syscall.IFLA_IFNAME:
|
||||||
|
base.Name = string(attr.Value[:len(attr.Value)-1])
|
||||||
|
case syscall.IFLA_MTU:
|
||||||
|
base.MTU = int(native.Uint32(attr.Value[0:4]))
|
||||||
|
case syscall.IFLA_LINK:
|
||||||
|
base.ParentIndex = int(native.Uint32(attr.Value[0:4]))
|
||||||
|
case syscall.IFLA_MASTER:
|
||||||
|
base.MasterIndex = int(native.Uint32(attr.Value[0:4]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("Link with index %d not found", index)
|
// Links that don't have IFLA_INFO_KIND are hardware devices
|
||||||
|
if link == nil {
|
||||||
|
link = &Device{}
|
||||||
|
}
|
||||||
|
*link.Attrs() = base
|
||||||
|
|
||||||
|
return link, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LinkList gets a list of link devices.
|
// LinkList gets a list of link devices.
|
||||||
@ -372,90 +455,20 @@ func LinkList() ([]Link, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
native := nl.NativeEndian()
|
|
||||||
res := make([]Link, 0)
|
res := make([]Link, 0)
|
||||||
|
|
||||||
for _, m := range msgs {
|
for _, m := range msgs {
|
||||||
msg := nl.DeserializeIfInfomsg(m)
|
link, err := LinkDeserialize(m)
|
||||||
|
|
||||||
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
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:
|
|
||||||
infos, err := nl.ParseRouteAttr(attr.Value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, info := range infos {
|
|
||||||
switch info.Attr.Type {
|
|
||||||
case nl.IFLA_INFO_KIND:
|
|
||||||
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{}
|
|
||||||
case "vxlan":
|
|
||||||
link = &Vxlan{}
|
|
||||||
default:
|
|
||||||
link = &Generic{LinkType: linkType}
|
|
||||||
}
|
|
||||||
case nl.IFLA_INFO_DATA:
|
|
||||||
data, err := nl.ParseRouteAttr(info.Value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
switch linkType {
|
|
||||||
case "vlan":
|
|
||||||
parseVlanData(link, data, native)
|
|
||||||
case "vxlan":
|
|
||||||
parseVxlanData(link, data, native)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case syscall.IFLA_ADDRESS:
|
|
||||||
var nonzero bool
|
|
||||||
for _, b := range attr.Value {
|
|
||||||
if b != 0 {
|
|
||||||
nonzero = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if nonzero {
|
|
||||||
base.HardwareAddr = attr.Value[:]
|
|
||||||
}
|
|
||||||
case syscall.IFLA_IFNAME:
|
|
||||||
base.Name = string(attr.Value[:len(attr.Value)-1])
|
|
||||||
case syscall.IFLA_MTU:
|
|
||||||
base.MTU = int(native.Uint32(attr.Value[0:4]))
|
|
||||||
case syscall.IFLA_LINK:
|
|
||||||
base.ParentIndex = int(native.Uint32(attr.Value[0:4]))
|
|
||||||
case syscall.IFLA_MASTER:
|
|
||||||
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)
|
res = append(res, link)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseVlanData(link Link, data []syscall.NetlinkRouteAttr, native binary.ByteOrder) {
|
func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||||
vlan := link.(*Vlan)
|
vlan := link.(*Vlan)
|
||||||
for _, datum := range data {
|
for _, datum := range data {
|
||||||
switch datum.Attr.Type {
|
switch datum.Attr.Type {
|
||||||
@ -465,7 +478,7 @@ func parseVlanData(link Link, data []syscall.NetlinkRouteAttr, native binary.Byt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr, native binary.ByteOrder) {
|
func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||||
vxlan := link.(*Vxlan)
|
vxlan := link.(*Vxlan)
|
||||||
for _, datum := range data {
|
for _, datum := range data {
|
||||||
switch datum.Attr.Type {
|
switch datum.Attr.Type {
|
||||||
|
24
link_test.go
24
link_test.go
@ -361,3 +361,27 @@ func TestLinkAddDelVxlan(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLinkByIndex(t *testing.T) {
|
||||||
|
dummy := &Dummy{LinkAttrs{Name: "dummy"}}
|
||||||
|
if err := LinkAdd(dummy); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
found, err := LinkByIndex(dummy.Index)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if found.Attrs().Index != dummy.Attrs().Index {
|
||||||
|
t.Fatalf("Indices don't match: %v != %v", found.Attrs().Index, dummy.Attrs().Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkDel(dummy)
|
||||||
|
|
||||||
|
// test not found
|
||||||
|
_, err = LinkByIndex(dummy.Attrs().Index)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("LinkByIndex(%v) found deleted link", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user