Skip to content
This repository has been archived by the owner on Jul 16, 2020. It is now read-only.

Commit

Permalink
Merge pull request #966 from sboeuf/master
Browse files Browse the repository at this point in the history
networking: libsnnet: Make API more explicit and get existing VNIC device by name
  • Loading branch information
mcastelino authored Dec 13, 2016
2 parents a4835f0 + fce606b commit d0bb7a1
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 10 deletions.
35 changes: 34 additions & 1 deletion networking/libsnnet/cn.go
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,12 @@ func createAndEnableVnic(vnic *Vnic, bridge *Bridge) error {
if err := vnic.Create(); err != nil {
return fmt.Errorf("VNIC creation failed %s %s", vnic.GlobalID, err.Error())
}
if err := vnic.SetHardwareAddr(*vnic.MACAddr); err != nil {

vnicPeer, err := initializeVnicPeer(vnic)
if err != nil {
return fmt.Errorf("VNIC Initialize Peer %s %s", vnic.GlobalID, err.Error())
}
if err := vnicPeer.SetHardwareAddr(*vnic.MACAddr); err != nil {
return fmt.Errorf("VNIC Set MAC Address %s %s", vnic.GlobalID, err.Error())
}
if err := vnic.SetMTU(vnic.MTU); err != nil {
Expand All @@ -990,6 +995,34 @@ func createAndEnableVnic(vnic *Vnic, bridge *Bridge) error {
return nil
}

func initializeVnicPeer(vnic *Vnic) (*Vnic, error) {
switch vnic.Role {
case TenantVM:
return vnic, nil
case TenantContainer:
vnicPeer, err := NewContainerVnic(vnic.GlobalID)
if err != nil {
return nil, err
}
vnicPeer.LinkName = vnic.PeerName()

vnicPeer.Link = &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{
Name: vnic.PeerName(),
},
PeerName: vnic.LinkName,
}

if err := vnicPeer.GetDeviceByName(vnicPeer.LinkName); err != nil {
return nil, err
}

return vnicPeer, nil
}

return nil, fmt.Errorf("Unknown VNIC tenant type")
}

func apiCancelled(cancel chan interface{}) bool {
select {
case <-cancel:
Expand Down
55 changes: 46 additions & 9 deletions networking/libsnnet/vnic.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package libsnnet

import (
"fmt"
"net"
"strings"
"syscall"
Expand Down Expand Up @@ -69,10 +70,12 @@ func (v *Vnic) PeerName() string {
if strings.HasPrefix(v.LinkName, prefixVnicHost) {
return strings.Replace(v.LinkName, prefixVnicHost, prefixVnicCont, 1)
}

if strings.HasPrefix(v.LinkName, prefixVnicCont) {
return strings.Replace(v.LinkName, prefixVnicCont, prefixVnicHost, 1)
}
return ""

return fmt.Sprintf("%s_peer", v.LinkName)
}

// GetDevice is used to associate with an existing VNIC provided it satisfies
Expand Down Expand Up @@ -119,6 +122,46 @@ func (v *Vnic) GetDevice() error {
return nil
}

// GetDeviceByName is used to associate with an existing VNIC relying on its
// link name instead of its alias. Returns error if the VNIC does not exist
func (v *Vnic) GetDeviceByName(linkName string) error {

link, err := netlink.LinkByName(linkName)
if err != nil {
return netError(v, "get device interface does not exist: %v", linkName)
}

switch v.Role {
case TenantVM:
vl, ok := link.(*netlink.GenericLink)
if !ok {
return netError(v, "get device incorrect interface type %v %v", linkName, link.Type())
}

// TODO: Why do both tun and tap interfaces return the type tun
if link.Type() != "tun" {
return netError(v, "get device incorrect interface type %v %v", linkName, link.Type())
}

if flags := uint(link.Attrs().Flags); (flags & syscall.IFF_TAP) == 0 {
return netError(v, "get device incorrect interface type %v %v", linkName, link)
}
v.LinkName = vl.Name
v.Link = vl
case TenantContainer:
vl, ok := link.(*netlink.Veth)
if !ok {
return netError(v, "get device incorrect interface type %v %v", linkName, link.Type())
}
v.LinkName = vl.Name
v.Link = vl
default:
return netError(v, " invalid or unsupported VNIC type %v", linkName)
}

return nil
}

func createVMVnic(v *Vnic) (link netlink.Link, err error) {

tap := &netlink.Tuntap{
Expand Down Expand Up @@ -347,14 +390,8 @@ func (v *Vnic) SetHardwareAddr(addr net.HardwareAddr) error {
/* Set by QEMU. */
case TenantContainer:
/* Need to set the MAC on the container side */
peerVeth := &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{
Name: v.PeerName(),
},
PeerName: v.LinkName,
}
if err := netlink.LinkSetHardwareAddr(peerVeth, addr); err != nil {
return netError(v, "link set peer mtu %v", err)
if err := netlink.LinkSetHardwareAddr(v.Link, addr); err != nil {
return netError(v, "link set hardware addr %v", err)
}
}

Expand Down
46 changes: 46 additions & 0 deletions networking/libsnnet/vnic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,52 @@ func TestVnicContainer_GetDevice(t *testing.T) {
performVnicOps(true, assert, vnic)
}

//Test ability to attach to an existing VNIC
//
//Tests the ability to attach to an existing
//VNIC and perform all VNIC operations on it
//
//Test is expected to pass
func TestVnic_GetDeviceByName(t *testing.T) {
assert := assert.New(t)
vnic1, _ := NewVnic("testvnic")
vnic1.LinkName = "testiface"

assert.Nil(vnic1.Create())
vnic, _ := NewVnic("testvnic")

assert.Nil(vnic.GetDeviceByName("testiface"))
assert.NotEqual(vnic.InterfaceName(), "")
assert.Equal(vnic.InterfaceName(), vnic1.InterfaceName())
assert.NotEqual(vnic1.PeerName(), "")
assert.Equal(vnic1.PeerName(), vnic.PeerName())

performVnicOps(true, assert, vnic)
}

//Test ability to attach to an existing Container VNIC
//
//Tests the ability to attach to an existing
//VNIC and perform all VNIC operations on it
//
//Test is expected to pass
func TestVnicContainer_GetDeviceByName(t *testing.T) {
assert := assert.New(t)

vnic1, err := NewContainerVnic("testvnic")
assert.Nil(err)
vnic1.LinkName = "testiface"

err = vnic1.Create()
assert.Nil(err)

vnic, err := NewContainerVnic("testvnic")
assert.Nil(err)

assert.Nil(vnic.GetDeviceByName("testiface"))
performVnicOps(true, assert, vnic)
}

//Tests VNIC attach to a bridge
//
//Tests all interactions between VNIC and Bridge
Expand Down

0 comments on commit d0bb7a1

Please sign in to comment.