Added VLAN and MAC VLAN device support to netlink

You can now create VLAN and MAC VLAN devices using netlink.
I've also added tests for both VLAN and MAC VLAN stuff.

Signed-off-by: Milos Gajdos <milosgajdos83@gmail.com> (github: milosgajdos83)
This commit is contained in:
Milos Gajdos 2014-09-27 04:15:34 +01:00
parent 267ba8f753
commit d90daa0cf7
2 changed files with 151 additions and 11 deletions

View File

@ -12,16 +12,25 @@ import (
)
const (
IFNAMSIZ = 16
DEFAULT_CHANGE = 0xFFFFFFFF
IFLA_INFO_KIND = 1
IFLA_INFO_DATA = 2
VETH_INFO_PEER = 1
IFLA_NET_NS_FD = 28
IFLA_ADDRESS = 1
SIOC_BRADDBR = 0x89a0
SIOC_BRDELBR = 0x89a1
SIOC_BRADDIF = 0x89a2
IFNAMSIZ = 16
DEFAULT_CHANGE = 0xFFFFFFFF
IFLA_INFO_KIND = 1
IFLA_INFO_DATA = 2
VETH_INFO_PEER = 1
IFLA_MACVLAN_MODE = 1
IFLA_VLAN_ID = 1
IFLA_NET_NS_FD = 28
IFLA_ADDRESS = 1
SIOC_BRADDBR = 0x89a0
SIOC_BRDELBR = 0x89a1
SIOC_BRADDIF = 0x89a2
)
const (
MACVLAN_MODE_PRIVATE = 1 << iota
MACVLAN_MODE_VEPA
MACVLAN_MODE_BRIDGE
MACVLAN_MODE_PASSTHRU
)
var nextSeqNr uint32
@ -702,6 +711,89 @@ func NetworkCreateVethPair(name1, name2 string) error {
return s.HandleAck(wb.Seq)
}
// Add a new VLAN interface with masterDev as its upper device
// This is identical to running:
// ip link add name $name link $masterdev type vlan id $id
func NetworkLinkAddVlan(masterDev, vlanDev string, vlanId uint16) error {
s, err := getNetlinkSocket()
if err != nil {
return err
}
defer s.Close()
wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
masterDevIfc, err := net.InterfaceByName(masterDev)
if err != nil {
return err
}
msg := newIfInfomsg(syscall.AF_UNSPEC)
wb.AddData(msg)
nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil)
newRtAttrChild(nest1, IFLA_INFO_KIND, nonZeroTerminated("vlan"))
nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil)
vlanData := make([]byte, 2)
native.PutUint16(vlanData, vlanId)
newRtAttrChild(nest2, IFLA_VLAN_ID, vlanData)
wb.AddData(nest1)
wb.AddData(uint32Attr(syscall.IFLA_LINK, uint32(masterDevIfc.Index)))
wb.AddData(newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(vlanDev)))
if err := s.Send(wb); err != nil {
return err
}
return s.HandleAck(wb.Seq)
}
// Add MAC VLAN network interface with masterDev as its upper device
// This is identical to running:
// ip link add name $name link $masterdev type macvlan mode $mode
func NetworkLinkAddMacVlan(masterDev, macVlanDev string, mode string) error {
s, err := getNetlinkSocket()
if err != nil {
return err
}
defer s.Close()
macVlan := map[string]uint32{
"private": MACVLAN_MODE_PRIVATE,
"vepa": MACVLAN_MODE_VEPA,
"bridge": MACVLAN_MODE_BRIDGE,
"passthru": MACVLAN_MODE_PASSTHRU,
}
wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
masterDevIfc, err := net.InterfaceByName(masterDev)
if err != nil {
return err
}
msg := newIfInfomsg(syscall.AF_UNSPEC)
wb.AddData(msg)
nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil)
newRtAttrChild(nest1, IFLA_INFO_KIND, nonZeroTerminated("macvlan"))
nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil)
macVlanData := make([]byte, 4)
native.PutUint32(macVlanData, macVlan[mode])
newRtAttrChild(nest2, IFLA_MACVLAN_MODE, macVlanData)
wb.AddData(nest1)
wb.AddData(uint32Attr(syscall.IFLA_LINK, uint32(masterDevIfc.Index)))
wb.AddData(newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(macVlanDev)))
if err := s.Send(wb); err != nil {
return err
}
return s.HandleAck(wb.Seq)
}
func networkLinkIpAction(action, flags int, ifa IfAddr) error {
s, err := getNetlinkSocket()
if err != nil {

View File

@ -200,6 +200,54 @@ func TestNetworkChangeName(t *testing.T) {
deleteLink(t, newName)
}
func TestNetworkLinkAddVlan(t *testing.T) {
if testing.Short() {
return
}
tl := struct {
name string
id uint16
}{
name: "tstVlan",
id: 32,
}
masterLink := testLink{"tstEth", "dummy"}
addLink(t, masterLink.name, masterLink.linkType)
defer deleteLink(t, masterLink.name)
if err := NetworkLinkAddVlan(masterLink.name, tl.name, tl.id); err != nil {
t.Fatalf("Unable to create %#v VLAN interface: %s", tl, err)
}
readLink(t, tl.name)
}
func TestNetworkLinkAddMacVlan(t *testing.T) {
if testing.Short() {
return
}
tl := struct {
name string
mode string
}{
name: "tstVlan",
mode: "private",
}
masterLink := testLink{"tstEth", "dummy"}
addLink(t, masterLink.name, masterLink.linkType)
defer deleteLink(t, masterLink.name)
if err := NetworkLinkAddMacVlan(masterLink.name, tl.name, tl.mode); err != nil {
t.Fatalf("Unable to create %#v MAC VLAN interface: %s", tl, err)
}
readLink(t, tl.name)
}
func TestAddDelNetworkIp(t *testing.T) {
if testing.Short() {
return
@ -252,7 +300,7 @@ func TestCreateVethPair(t *testing.T) {
}
//
// netlink package test which do not use RTNETLINK
// netlink package tests which do not use RTNETLINK
//
func TestCreateBridgeWithMac(t *testing.T) {
if testing.Short() {