Parse IFLA_PROTINFO in LinkDeserialize

Extract and parse IFLA_PROTINFO fields from RTM_NEWLINK AF_BRIDGE
netlink messages.
This commit is contained in:
Martynas Pumputis 2016-11-24 18:32:30 +00:00 committed by Vish Ishaya
parent a4f22d8ad2
commit 266f02d3a8
4 changed files with 89 additions and 21 deletions

View File

@ -35,6 +35,7 @@ type LinkAttrs struct {
Promisc int
Xdp *LinkXdp
EncapType string
Protinfo *Protinfo
}
// NewLinkAttrs returns LinkAttrs structure filled with default values

View File

@ -953,7 +953,7 @@ func execGetLink(req *nl.NetlinkRequest) (Link, error) {
return nil, fmt.Errorf("Link not found")
case len(msgs) == 1:
return LinkDeserialize(msgs[0])
return LinkDeserialize(nil, msgs[0])
default:
return nil, fmt.Errorf("More than one link found")
@ -962,7 +962,7 @@ func execGetLink(req *nl.NetlinkRequest) (Link, error) {
// linkDeserialize deserializes a raw message received from netlink into
// a link object.
func LinkDeserialize(m []byte) (Link, error) {
func LinkDeserialize(hdr *syscall.NlMsghdr, m []byte) (Link, error) {
msg := nl.DeserializeIfInfomsg(m)
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
@ -1074,6 +1074,15 @@ func LinkDeserialize(m []byte) (Link, error) {
return nil, err
}
base.Xdp = xdp
case syscall.IFLA_PROTINFO | syscall.NLA_F_NESTED:
if hdr != nil && hdr.Type == syscall.RTM_NEWLINK &&
msg.Family == syscall.AF_BRIDGE {
attrs, err := nl.ParseRouteAttr(attr.Value[:])
if err != nil {
return nil, err
}
base.Protinfo = parseProtinfo(attrs)
}
}
}
// Links that don't have IFLA_INFO_KIND are hardware devices
@ -1108,7 +1117,7 @@ func (h *Handle) LinkList() ([]Link, error) {
var res []Link
for _, m := range msgs {
link, err := LinkDeserialize(m)
link, err := LinkDeserialize(nil, m)
if err != nil {
return nil, err
}
@ -1157,7 +1166,7 @@ func linkSubscribe(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-cha
}
for _, m := range msgs {
ifmsg := nl.DeserializeIfInfomsg(m.Data)
link, err := LinkDeserialize(m.Data)
link, err := LinkDeserialize(&m.Header, m.Data)
if err != nil {
return
}

View File

@ -1006,3 +1006,55 @@ func TestLinkAddDelVti(t *testing.T) {
Local: net.IPv4(127, 0, 0, 1),
Remote: net.IPv4(127, 0, 0, 1)})
}
func TestLinkSubscribeWithProtinfo(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
master := &Bridge{LinkAttrs{Name: "foo"}}
if err := LinkAdd(master); err != nil {
t.Fatal(err)
}
slave := &Veth{
LinkAttrs: LinkAttrs{
Name: "bar",
TxQLen: testTxQLen,
MTU: 1400,
MasterIndex: master.Attrs().Index,
},
PeerName: "bar-peer",
}
if err := LinkAdd(slave); err != nil {
t.Fatal(err)
}
ch := make(chan LinkUpdate)
done := make(chan struct{})
defer close(done)
if err := LinkSubscribe(ch, done); err != nil {
t.Fatal(err)
}
if err := LinkSetHairpin(slave, true); err != nil {
t.Fatal(err)
}
select {
case update := <-ch:
if !(update.Attrs().Name == "bar" && update.Attrs().Protinfo != nil &&
update.Attrs().Protinfo.Hairpin) {
t.Fatal("Hairpin update not received as expected")
}
case <-time.After(time.Minute):
t.Fatal("Hairpin update timed out")
}
if err := LinkDel(slave); err != nil {
t.Fatal(err)
}
if err := LinkDel(master); err != nil {
t.Fatal(err)
}
}

View File

@ -40,25 +40,31 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
if err != nil {
return pi, err
}
var pi Protinfo
for _, info := range infos {
switch info.Attr.Type {
case nl.IFLA_BRPORT_MODE:
pi.Hairpin = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_GUARD:
pi.Guard = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_FAST_LEAVE:
pi.FastLeave = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_PROTECT:
pi.RootBlock = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_LEARNING:
pi.Learning = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_UNICAST_FLOOD:
pi.Flood = byteToBool(info.Value[0])
}
}
pi = *parseProtinfo(infos)
return pi, nil
}
}
return pi, fmt.Errorf("Device with index %d not found", base.Index)
}
func parseProtinfo(infos []syscall.NetlinkRouteAttr) *Protinfo {
var pi Protinfo
for _, info := range infos {
switch info.Attr.Type {
case nl.IFLA_BRPORT_MODE:
pi.Hairpin = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_GUARD:
pi.Guard = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_FAST_LEAVE:
pi.FastLeave = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_PROTECT:
pi.RootBlock = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_LEARNING:
pi.Learning = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_UNICAST_FLOOD:
pi.Flood = byteToBool(info.Value[0])
}
}
return &pi
}