Skip to content
This repository has been archived by the owner on May 12, 2021. It is now read-only.

Commit

Permalink
Merge pull request #852 from amshinde/ipvlan
Browse files Browse the repository at this point in the history
Add support for ipvlan network driver
  • Loading branch information
bergwolf authored Oct 29, 2018
2 parents 95386fb + 0acbbf0 commit 6d17e27
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 1 deletion.
8 changes: 8 additions & 0 deletions virtcontainers/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ const (

// TapEndpointType is tap network interface.
TapEndpointType EndpointType = "tap"

// IPVlanEndpointType is ipvlan network interface.
IPVlanEndpointType EndpointType = "ipvlan"
)

// Set sets an endpoint type based on the input string.
Expand All @@ -70,6 +73,9 @@ func (endpointType *EndpointType) Set(value string) error {
case "tap":
*endpointType = TapEndpointType
return nil
case "ipvlan":
*endpointType = IPVlanEndpointType
return nil
default:
return fmt.Errorf("Unknown endpoint type %s", value)
}
Expand All @@ -90,6 +96,8 @@ func (endpointType *EndpointType) String() string {
return string(MacvtapEndpointType)
case TapEndpointType:
return string(TapEndpointType)
case IPVlanEndpointType:
return string(IPVlanEndpointType)
default:
return ""
}
Expand Down
120 changes: 120 additions & 0 deletions virtcontainers/ipvlan_endpoint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//

package virtcontainers

import (
"fmt"

"github.com/containernetworking/plugins/pkg/ns"
)

// IPVlanEndpoint represents a ipvlan endpoint that is bridged to the VM
type IPVlanEndpoint struct {
NetPair NetworkInterfacePair
EndpointProperties NetworkInfo
EndpointType EndpointType
PCIAddr string
}

func createIPVlanNetworkEndpoint(idx int, ifName string) (*IPVlanEndpoint, error) {
if idx < 0 {
return &IPVlanEndpoint{}, fmt.Errorf("invalid network endpoint index: %d", idx)
}

// Use tc filtering for ipvlan, since the other inter networking models will
// not work for ipvlan.
interworkingModel := NetXConnectTCFilterModel
netPair, err := createNetworkInterfacePair(idx, ifName, interworkingModel)
if err != nil {
return nil, err
}

endpoint := &IPVlanEndpoint{
NetPair: netPair,
EndpointType: IPVlanEndpointType,
}
if ifName != "" {
endpoint.NetPair.VirtIface.Name = ifName
}

return endpoint, nil
}

// Properties returns properties of the interface.
func (endpoint *IPVlanEndpoint) Properties() NetworkInfo {
return endpoint.EndpointProperties
}

// Name returns name of the veth interface in the network pair.
func (endpoint *IPVlanEndpoint) Name() string {
return endpoint.NetPair.VirtIface.Name
}

// HardwareAddr returns the mac address that is assigned to the tap interface
// in th network pair.
func (endpoint *IPVlanEndpoint) HardwareAddr() string {
return endpoint.NetPair.TAPIface.HardAddr
}

// Type identifies the endpoint as a virtual endpoint.
func (endpoint *IPVlanEndpoint) Type() EndpointType {
return endpoint.EndpointType
}

// SetProperties sets the properties for the endpoint.
func (endpoint *IPVlanEndpoint) SetProperties(properties NetworkInfo) {
endpoint.EndpointProperties = properties
}

// PciAddr returns the PCI address of the endpoint.
func (endpoint *IPVlanEndpoint) PciAddr() string {
return endpoint.PCIAddr
}

// SetPciAddr sets the PCI address of the endpoint.
func (endpoint *IPVlanEndpoint) SetPciAddr(pciAddr string) {
endpoint.PCIAddr = pciAddr
}

// NetworkPair returns the network pair of the endpoint.
func (endpoint *IPVlanEndpoint) NetworkPair() *NetworkInterfacePair {
return &endpoint.NetPair
}

// Attach for virtual endpoint bridges the network pair and adds the
// tap interface of the network pair to the hypervisor.
func (endpoint *IPVlanEndpoint) Attach(h hypervisor) error {
if err := xconnectVMNetwork(endpoint, true, h.hypervisorConfig().NumVCPUs, h.hypervisorConfig().DisableVhostNet); err != nil {
networkLogger().WithError(err).Error("Error bridging virtual ep")
return err
}

return h.addDevice(endpoint, netDev)
}

// Detach for the virtual endpoint tears down the tap and bridge
// created for the veth interface.
func (endpoint *IPVlanEndpoint) Detach(netNsCreated bool, netNsPath string) error {
// The network namespace would have been deleted at this point
// if it has not been created by virtcontainers.
if !netNsCreated {
return nil
}

return doNetNS(netNsPath, func(_ ns.NetNS) error {
return xconnectVMNetwork(endpoint, false, 0, false)
})
}

// HotAttach for physical endpoint not supported yet
func (endpoint *IPVlanEndpoint) HotAttach(h hypervisor) error {
return fmt.Errorf("IPVlanEndpoint does not support Hot attach")
}

// HotDetach for physical endpoint not supported yet
func (endpoint *IPVlanEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
return fmt.Errorf("IPVlanEndpoint does not support Hot detach")
}
50 changes: 50 additions & 0 deletions virtcontainers/ipvlan_endpoint_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//

package virtcontainers

import (
"net"
"reflect"
"testing"
)

func TestCreateIPVlanEndpoint(t *testing.T) {
macAddr := net.HardwareAddr{0x02, 0x00, 0xCA, 0xFE, 0x00, 0x04}

expected := &IPVlanEndpoint{
NetPair: NetworkInterfacePair{
TapInterface: TapInterface{
ID: "uniqueTestID-5",
Name: "br5_kata",
TAPIface: NetworkInterface{
Name: "tap5_kata",
},
},
VirtIface: NetworkInterface{
Name: "eth5",
HardAddr: macAddr.String(),
},

NetInterworkingModel: NetXConnectTCFilterModel,
},
EndpointType: IPVlanEndpointType,
}

result, err := createIPVlanNetworkEndpoint(5, "")
if err != nil {
t.Fatal(err)
}

// the resulting ID will be random - so let's overwrite to test the rest of the flow
result.NetPair.ID = "uniqueTestID-5"

// the resulting mac address will be random - so lets overwrite it
result.NetPair.VirtIface.HardAddr = macAddr.String()

if reflect.DeepEqual(result, expected) == false {
t.Fatalf("\nGot: %+v, \n\nExpected: %+v", result, expected)
}
}
8 changes: 8 additions & 0 deletions virtcontainers/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,8 @@ func getLinkForEndpoint(endpoint Endpoint, netHandle *netlink.Handle) (netlink.L
link = &netlink.Veth{}
case *BridgedMacvlanEndpoint:
link = &netlink.Macvlan{}
case *IPVlanEndpoint:
link = &netlink.IPVlan{}
default:
return nil, fmt.Errorf("Unexpected endpointType %s", ep.Type())
}
Expand Down Expand Up @@ -488,6 +490,10 @@ func getLinkByName(netHandle *netlink.Handle, name string, expectedLink netlink.
if l, ok := link.(*netlink.Macvlan); ok {
return l, nil
}
case (&netlink.IPVlan{}).Type():
if l, ok := link.(*netlink.IPVlan); ok {
return l, nil
}
default:
return nil, fmt.Errorf("Unsupported link type %s", expectedLink.Type())
}
Expand Down Expand Up @@ -1405,6 +1411,8 @@ func createEndpoint(netInfo NetworkInfo, idx int, model NetInterworkingModel) (E
endpoint, err = createTapNetworkEndpoint(idx, netInfo.Iface.Name)
} else if netInfo.Iface.Type == "veth" {
endpoint, err = createVethNetworkEndpoint(idx, netInfo.Iface.Name, model)
} else if netInfo.Iface.Type == "ipvlan" {
endpoint, err = createIPVlanNetworkEndpoint(idx, netInfo.Iface.Name)
} else {
return nil, fmt.Errorf("Unsupported network interface")
}
Expand Down
2 changes: 1 addition & 1 deletion virtcontainers/qemu_arch_base.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ func networkModelToQemuType(model NetInterworkingModel) govmmQemu.NetDeviceType

func (q *qemuArchBase) appendNetwork(devices []govmmQemu.Device, endpoint Endpoint) []govmmQemu.Device {
switch ep := endpoint.(type) {
case *VethEndpoint, *BridgedMacvlanEndpoint:
case *VethEndpoint, *BridgedMacvlanEndpoint, *IPVlanEndpoint:
netPair := ep.NetworkPair()
devices = append(devices,
govmmQemu.NetDevice{
Expand Down

0 comments on commit 6d17e27

Please sign in to comment.