Fixed rtnetlink attributes packaging into netlink message.

I've also added NetworkLinkDel() function which allows deleting
of the existing network links.

Docker-DCO-1.1-Signed-off-by: Milos Gajdos <milosgajdos83@gmail.com> (github: milosgajdos83)
This commit is contained in:
Milos Gajdos 2014-08-04 18:29:06 +01:00
parent f538117a7b
commit c5f4d90da5
3 changed files with 77 additions and 15 deletions

View File

@ -189,13 +189,15 @@ func newRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr {
} }
func (a *RtAttr) Len() int { func (a *RtAttr) Len() int {
if len(a.children) == 0 {
return (syscall.SizeofRtAttr + len(a.Data))
}
l := 0 l := 0
for _, child := range a.children { for _, child := range a.children {
l += child.Len() + syscall.SizeofRtAttr l += child.Len()
}
if l == 0 {
l++
} }
l += syscall.SizeofRtAttr
return rtaAlignOf(l + len(a.Data)) return rtaAlignOf(l + len(a.Data))
} }
@ -203,7 +205,7 @@ func (a *RtAttr) ToWireFormat() []byte {
native := nativeEndian() native := nativeEndian()
length := a.Len() length := a.Len()
buf := make([]byte, rtaAlignOf(length+syscall.SizeofRtAttr)) buf := make([]byte, rtaAlignOf(length))
if a.Data != nil { if a.Data != nil {
copy(buf[4:], a.Data) copy(buf[4:], a.Data)
@ -216,11 +218,10 @@ func (a *RtAttr) ToWireFormat() []byte {
} }
} }
if l := uint16(rtaAlignOf(length)); l != 0 { if l := uint16(length); l != 0 {
native.PutUint16(buf[0:2], l+1) native.PutUint16(buf[0:2], l)
} }
native.PutUint16(buf[2:4], a.Type) native.PutUint16(buf[2:4], a.Type)
return buf return buf
} }
@ -700,6 +701,10 @@ func nonZeroTerminated(s string) []byte {
// Add a new network link of a specified type. This is identical to // Add a new network link of a specified type. This is identical to
// running: ip add link $name type $linkType // running: ip add link $name type $linkType
func NetworkLinkAdd(name string, linkType string) error { func NetworkLinkAdd(name string, linkType string) error {
if name == "" || linkType == "" {
return fmt.Errorf("Neither link name nor link type can be empty!")
}
s, err := getNetlinkSocket() s, err := getNetlinkSocket()
if err != nil { if err != nil {
return err return err
@ -711,15 +716,43 @@ func NetworkLinkAdd(name string, linkType string) error {
msg := newIfInfomsg(syscall.AF_UNSPEC) msg := newIfInfomsg(syscall.AF_UNSPEC)
wb.AddData(msg) wb.AddData(msg)
if name != "" { linkInfo := newRtAttr(syscall.IFLA_LINKINFO, nil)
nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name)) newRtAttrChild(linkInfo, IFLA_INFO_KIND, nonZeroTerminated(linkType))
wb.AddData(nameData) wb.AddData(linkInfo)
nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name))
wb.AddData(nameData)
if err := s.Send(wb); err != nil {
return err
} }
kindData := newRtAttr(IFLA_INFO_KIND, nonZeroTerminated(linkType)) return s.HandleAck(wb.Seq)
}
infoData := newRtAttr(syscall.IFLA_LINKINFO, kindData.ToWireFormat()) // Delete a network link. This is identical to
wb.AddData(infoData) // running: ip link del $name
func NetworkLinkDel(name string) error {
if name == "" {
return fmt.Errorf("Network link name can not be empty!")
}
s, err := getNetlinkSocket()
if err != nil {
return err
}
defer s.Close()
iface, err := net.InterfaceByName(name)
if err != nil {
return err
}
wb := newNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK)
msg := newIfInfomsg(syscall.AF_UNSPEC)
msg.Index = int32(iface.Index)
wb.AddData(msg)
if err := s.Send(wb); err != nil { if err := s.Send(wb); err != nil {
return err return err

View File

@ -27,10 +27,35 @@ func TestCreateBridgeWithMac(t *testing.T) {
} }
if _, err := net.InterfaceByName(name); err == nil { if _, err := net.InterfaceByName(name); err == nil {
t.Fatal("expected error getting interface because bridge was deleted") t.Fatal("expected error getting interface because %s bridge was deleted", name)
} }
} }
func TestCreateBridgeLink(t *testing.T) {
if testing.Short() {
return
}
name := "mybrlink"
if err := NetworkLinkAdd(name, "bridge"); err != nil {
log.Fatal(err)
}
if _, err := net.InterfaceByName(name); err != nil {
t.Fatal(err)
}
if err := NetworkLinkDel(name); err != nil {
t.Fatal(err)
}
if _, err := net.InterfaceByName(name); err == nil {
t.Fatal("expected error getting interface because %s bridge was deleted", name)
}
}
func TestCreateVethPair(t *testing.T) { func TestCreateVethPair(t *testing.T) {
if testing.Short() { if testing.Short() {
return return

View File

@ -19,6 +19,10 @@ func NetworkLinkAdd(name string, linkType string) error {
return ErrNotImplemented return ErrNotImplemented
} }
func NetworkLinkDel(name string) error {
return ErrNotImplemented
}
func NetworkLinkUp(iface *net.Interface) error { func NetworkLinkUp(iface *net.Interface) error {
return ErrNotImplemented return ErrNotImplemented
} }