From 0acbbf06517335fdad6d1ba3f9453dca8f764629 Mon Sep 17 00:00:00 2001 From: Archana Shinde Date: Wed, 24 Oct 2018 17:13:25 -0700 Subject: [PATCH] network: Add support for ipvlan Support ipvlan interfaces by setting up tc redirect rules. Fixes #591 Signed-off-by: Archana Shinde --- virtcontainers/endpoint.go | 8 ++ virtcontainers/ipvlan_endpoint.go | 120 +++++++++++++++++++++++++ virtcontainers/ipvlan_endpoint_test.go | 50 +++++++++++ virtcontainers/network.go | 8 ++ virtcontainers/qemu_arch_base.go | 2 +- 5 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 virtcontainers/ipvlan_endpoint.go create mode 100644 virtcontainers/ipvlan_endpoint_test.go diff --git a/virtcontainers/endpoint.go b/virtcontainers/endpoint.go index ea08f00de..978da2dc1 100644 --- a/virtcontainers/endpoint.go +++ b/virtcontainers/endpoint.go @@ -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. @@ -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) } @@ -90,6 +96,8 @@ func (endpointType *EndpointType) String() string { return string(MacvtapEndpointType) case TapEndpointType: return string(TapEndpointType) + case IPVlanEndpointType: + return string(IPVlanEndpointType) default: return "" } diff --git a/virtcontainers/ipvlan_endpoint.go b/virtcontainers/ipvlan_endpoint.go new file mode 100644 index 000000000..beab38d86 --- /dev/null +++ b/virtcontainers/ipvlan_endpoint.go @@ -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") +} diff --git a/virtcontainers/ipvlan_endpoint_test.go b/virtcontainers/ipvlan_endpoint_test.go new file mode 100644 index 000000000..945427c80 --- /dev/null +++ b/virtcontainers/ipvlan_endpoint_test.go @@ -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) + } +} diff --git a/virtcontainers/network.go b/virtcontainers/network.go index 86f5a3b34..55f13c07e 100644 --- a/virtcontainers/network.go +++ b/virtcontainers/network.go @@ -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()) } @@ -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()) } @@ -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") } diff --git a/virtcontainers/qemu_arch_base.go b/virtcontainers/qemu_arch_base.go index 707afc95b..b8fb5cd20 100644 --- a/virtcontainers/qemu_arch_base.go +++ b/virtcontainers/qemu_arch_base.go @@ -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{