Skip to content

Commit

Permalink
Remove Docker Support for Antrea Windows
Browse files Browse the repository at this point in the history
This patch removes the support for Docker from the Antrea Windows Agent.
The specific changes made in this commit include modifying the CNI call to return an error when the runtime
is identified as Docker on Windows and deleting related functions.

Signed-off-by: Shuyang Xin <gavinx@vmware.com>
  • Loading branch information
XinShuYang committed Apr 1, 2024
1 parent 7e3aa12 commit b13bf49
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 262 deletions.
4 changes: 0 additions & 4 deletions pkg/agent/cniserver/interface_configuration_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,3 @@ func isVeth(link netlink.Link) bool {
_, isVeth := link.(*netlink.Veth)
return isVeth
}

func getOVSInterfaceType(ovsPortName string) int {
return defaultOVSInterfaceType
}
59 changes: 6 additions & 53 deletions pkg/agent/cniserver/interface_configuration_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ var (
getNetInterfaceAddrsFunc = getNetInterfaceAddrs
createHnsEndpointFunc = createHnsEndpoint
getNamespaceEndpointIDsFunc = hcn.GetNamespaceEndpointIds
hotAttachEndpointFunc = hcsshim.HotAttachEndpoint
attachEndpointInNamespaceFunc = attachEndpointInNamespace
isContainerAttachOnEndpointFunc = isContainerAttachOnEndpoint
getHcnEndpointByIDFunc = hcn.GetEndpointByID
deleteHnsEndpointFunc = deleteHnsEndpoint
removeEndpointFromNamespaceFunc = hcn.RemoveNamespaceEndpoint
Expand Down Expand Up @@ -221,49 +219,17 @@ func (ic *ifConfigurator) createContainerLink(endpointName string, result *curre
// attachContainerLink takes the result of the IPAM plugin, and adds the appropriate IP
// addresses and routes to the interface.
// For different CRI runtimes we need to use the appropriate Windows container API:
// - Docker runtime: HNS API
// - containerd runtime: HCS API
func attachContainerLink(ep *hcsshim.HNSEndpoint, containerID, sandbox, containerIFDev string) (*current.Interface, error) {
var attached bool
var err error
var hcnEp *hcn.HostComputeEndpoint
if isDockerContainer(sandbox) {
// Docker runtime
attached, err = isContainerAttachOnEndpointFunc(ep, containerID)
if err != nil {
return nil, err
}
} else {
// containerd runtime
if hcnEp, err = getHcnEndpointByIDFunc(ep.Id); err != nil {
return nil, err
}
attachedEpIds, err := getNamespaceEndpointIDsFunc(sandbox)
if err != nil {
return nil, err
}
for _, existingEP := range attachedEpIds {
if existingEP == hcnEp.Id {
attached = true
break
}
}
}

if attached {
klog.V(2).Infof("HNS Endpoint %s already attached on container %s", ep.Id, containerID)
} else {
if hcnEp == nil {
// Docker runtime
if err := hotAttachEndpointFunc(containerID, ep.Id); err != nil {
return nil, err
}
} else {
// containerd runtime
if err := attachEndpointInNamespaceFunc(hcnEp, sandbox); err != nil {
return nil, err
}
}
if hcnEp, err = getHcnEndpointByIDFunc(ep.Id); err != nil {
return nil, err
}

if err := attachEndpointInNamespaceFunc(hcnEp, sandbox); err != nil {
return nil, err
}
containerIface := &current.Interface{
Name: containerIFDev,
Expand All @@ -273,10 +239,6 @@ func attachContainerLink(ep *hcsshim.HNSEndpoint, containerID, sandbox, containe
return containerIface, nil
}

func isContainerAttachOnEndpoint(endpoint *hcsshim.HNSEndpoint, containerID string) (bool, error) {
return endpoint.IsAttached(containerID)
}

func attachEndpointInNamespace(hcnEp *hcn.HostComputeEndpoint, sandbox string) error {
return hcnEp.NamespaceAttach(sandbox)
}
Expand Down Expand Up @@ -485,15 +447,6 @@ func (ic *ifConfigurator) getInterceptedInterfaces(
return nil, nil, errors.New("getInterceptedInterfaces is unsupported on Windows")
}

// getOVSInterfaceType returns "internal". Windows uses internal OVS interface for container vNIC.
func getOVSInterfaceType(ovsPortName string) int {
ifaceName := fmt.Sprintf("vEthernet (%s)", ovsPortName)
if !hostInterfaceExistsFunc(ifaceName) {
return defaultOVSInterfaceType
}
return internalOVSInterfaceType
}

func (ic *ifConfigurator) addPostInterfaceCreateHook(containerID, endpointName string, containerAccess *containerAccessArbitrator, hook postInterfaceCreateHook) error {
if containerAccess == nil {
return fmt.Errorf("container lock cannot be null")
Expand Down
66 changes: 5 additions & 61 deletions pkg/agent/cniserver/pod_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,6 @@ const (
)

const (
defaultOVSInterfaceType int = iota //nolint suppress deadcode check for windows
internalOVSInterfaceType

defaultIFDevName = "eth0"
)

Expand Down Expand Up @@ -265,15 +262,11 @@ func (pc *podConfigurator) configureInterfacesCommon(
func (pc *podConfigurator) createOVSPort(ovsPortName string, ovsAttachInfo map[string]interface{}, vlanID uint16) (string, error) {
var portUUID string
var err error
switch getOVSInterfaceType(ovsPortName) {
case internalOVSInterfaceType:
portUUID, err = pc.ovsBridgeClient.CreateInternalPort(ovsPortName, 0, "", ovsAttachInfo)
default:
if vlanID == 0 {
portUUID, err = pc.ovsBridgeClient.CreatePort(ovsPortName, ovsPortName, ovsAttachInfo)
} else {
portUUID, err = pc.ovsBridgeClient.CreateAccessPort(ovsPortName, ovsPortName, ovsAttachInfo, vlanID)
}

if vlanID == 0 {
portUUID, err = pc.ovsBridgeClient.CreatePort(ovsPortName, ovsPortName, ovsAttachInfo)
} else {
portUUID, err = pc.ovsBridgeClient.CreateAccessPort(ovsPortName, ovsPortName, ovsAttachInfo, vlanID)
}
if err != nil {
klog.Errorf("Failed to add OVS port %s, remove from local cache: %v", ovsPortName, err)
Expand Down Expand Up @@ -493,55 +486,6 @@ func (pc *podConfigurator) reconcile(pods []corev1.Pod, containerAccess *contain
return nil
}

func (pc *podConfigurator) connectInterfaceToOVSCommon(ovsPortName, netNS string, containerConfig *interfacestore.InterfaceConfig) error {
// create OVS Port and add attach container configuration into external_ids
containerID := containerConfig.ContainerID
klog.V(2).Infof("Adding OVS port %s for container %s", ovsPortName, containerID)
ovsAttachInfo := BuildOVSPortExternalIDs(containerConfig)
portUUID, err := pc.createOVSPort(ovsPortName, ovsAttachInfo, containerConfig.VLANID)
if err != nil {
return fmt.Errorf("failed to add OVS port for container %s: %v", containerID, err)
}
// Remove OVS port if any failure occurs in later manipulation.
defer func() {
if err != nil {
_ = pc.ovsBridgeClient.DeletePort(portUUID)
}
}()

var ofPort int32
// Not needed for a secondary network interface.
if !pc.isSecondaryNetwork {
// GetOFPort will wait for up to 1 second for OVSDB to report the OFPort number.
ofPort, err = pc.ovsBridgeClient.GetOFPort(ovsPortName, false)
if err != nil {
return fmt.Errorf("failed to get of_port of OVS port %s: %v", ovsPortName, err)
}
klog.V(2).InfoS("Setting up Openflow entries for Pod interface", "container", containerID, "port", ovsPortName)
if err = pc.ofClient.InstallPodFlows(ovsPortName, containerConfig.IPs, containerConfig.MAC, uint32(ofPort), containerConfig.VLANID, nil); err != nil {
return fmt.Errorf("failed to add Openflow entries for container %s: %v", containerID, err)
}
}

containerConfig.OVSPortConfig = &interfacestore.OVSPortConfig{PortUUID: portUUID, OFPort: ofPort}
// Add containerConfig into local cache
pc.ifaceStore.AddInterface(containerConfig)

// Not needed for a secondary network interface.
if !pc.isSecondaryNetwork {
// Notify the Pod update event to required components.
event := agenttypes.PodUpdate{
PodName: containerConfig.PodName,
PodNamespace: containerConfig.PodNamespace,
ContainerID: containerConfig.ContainerID,
NetNS: netNS,
IsAdd: true,
}
pc.podUpdateNotifier.Notify(event)
}
return nil
}

// disconnectInterfaceFromOVS disconnects an existing interface from ovs br-int.
func (pc *podConfigurator) disconnectInterfaceFromOVS(containerConfig *interfacestore.InterfaceConfig) error {
containerID := containerConfig.ContainerID
Expand Down
52 changes: 52 additions & 0 deletions pkg/agent/cniserver/pod_configuration_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@
package cniserver

import (
"fmt"

current "github.com/containernetworking/cni/pkg/types/100"
"k8s.io/klog/v2"

agenttypes "antrea.io/antrea/pkg/agent/types"
"antrea.io/antrea/pkg/agent/cniserver/ipam"
"antrea.io/antrea/pkg/agent/interfacestore"
)
Expand All @@ -38,6 +41,55 @@ func (pc *podConfigurator) connectInterfaceToOVS(
return containerConfig, pc.connectInterfaceToOVSCommon(ovsPortName, netNS, containerConfig)
}

func (pc *podConfigurator) connectInterfaceToOVSCommon(ovsPortName, netNS string, containerConfig *interfacestore.InterfaceConfig) error {
// create OVS Port and add attach container configuration into external_ids
containerID := containerConfig.ContainerID
klog.V(2).Infof("Adding OVS port %s for container %s", ovsPortName, containerID)
ovsAttachInfo := BuildOVSPortExternalIDs(containerConfig)
portUUID, err := pc.createOVSPort(ovsPortName, ovsAttachInfo, containerConfig.VLANID)
if err != nil {
return fmt.Errorf("failed to add OVS port for container %s: %v", containerID, err)
}
// Remove OVS port if any failure occurs in later manipulation.
defer func() {
if err != nil {
_ = pc.ovsBridgeClient.DeletePort(portUUID)
}
}()

var ofPort int32
// Not needed for a secondary network interface.
if !pc.isSecondaryNetwork {
// GetOFPort will wait for up to 1 second for OVSDB to report the OFPort number.
ofPort, err = pc.ovsBridgeClient.GetOFPort(ovsPortName, false)
if err != nil {
return fmt.Errorf("failed to get of_port of OVS port %s: %v", ovsPortName, err)
}
klog.V(2).InfoS("Setting up Openflow entries for Pod interface", "container", containerID, "port", ovsPortName)
if err = pc.ofClient.InstallPodFlows(ovsPortName, containerConfig.IPs, containerConfig.MAC, uint32(ofPort), containerConfig.VLANID, nil); err != nil {
return fmt.Errorf("failed to add Openflow entries for container %s: %v", containerID, err)
}
}

containerConfig.OVSPortConfig = &interfacestore.OVSPortConfig{PortUUID: portUUID, OFPort: ofPort}
// Add containerConfig into local cache
pc.ifaceStore.AddInterface(containerConfig)

// Not needed for a secondary network interface.
if !pc.isSecondaryNetwork {
// Notify the Pod update event to required components.
event := agenttypes.PodUpdate{
PodName: containerConfig.PodName,
PodNamespace: containerConfig.PodNamespace,
ContainerID: containerConfig.ContainerID,
NetNS: netNS,
IsAdd: true,
}
pc.podUpdateNotifier.Notify(event)
}
return nil
}

func (pc *podConfigurator) configureInterfaces(
podName, podNamespace, containerID, containerNetNS string,
containerIFDev string, mtu int, sriovVFDeviceID string,
Expand Down
7 changes: 2 additions & 5 deletions pkg/agent/cniserver/pod_configuration_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type fakeInterfaceConfigurator struct {
configureContainerLinkError error
removeContainerLinkError error
advertiseContainerAddrError error
ovsInterfaceTypeMapping map[string]int
ovsInterfaceTypeMapping string
validateVFRepInterfaceError error
validateContainerPeerInterfaceError error
containerVethPair *vethPair
Expand Down Expand Up @@ -248,27 +248,24 @@ func TestCreateOVSPort(t *testing.T) {
for _, tc := range []struct {
name string
portName string
portType int
vlanID uint16
createOVSPort bool
createOVSAccessPort bool
}{
{
name: "create-general-port",
portName: "p1",
portType: defaultOVSInterfaceType,
vlanID: 0,
createOVSPort: true,
}, {
name: "create-access-port",
portName: "p3",
portType: defaultOVSInterfaceType,
vlanID: 10,
createOVSAccessPort: true,
},
} {
t.Run(tc.name, func(t *testing.T) {
testIfaceConfigurator := &fakeInterfaceConfigurator{ovsInterfaceTypeMapping: map[string]int{tc.portName: tc.portType}}
testIfaceConfigurator := &fakeInterfaceConfigurator{ovsInterfaceTypeMapping: tc.portName}
podConfigurator := createPodConfigurator(controller, testIfaceConfigurator)
containerConfig := buildContainerConfig(tc.portName, containerID, podName, podNamespace, &current.Interface{Mac: "01:02:03:04:05:06"}, ipamResult.IPs, tc.vlanID)
attachInfo := BuildOVSPortExternalIDs(containerConfig)
Expand Down
11 changes: 0 additions & 11 deletions pkg/agent/cniserver/pod_configuration_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"antrea.io/antrea/pkg/agent/cniserver/ipam"
"antrea.io/antrea/pkg/agent/interfacestore"
"antrea.io/antrea/pkg/agent/types"
"antrea.io/antrea/pkg/agent/util"
"antrea.io/antrea/pkg/util/k8s"
)

Expand Down Expand Up @@ -72,20 +71,10 @@ func (pc *podConfigurator) connectInterfaceToOVS(
// Use the outer veth interface name as the OVS port name.
ovsPortName := hostIface.Name
containerConfig := buildContainerConfig(ovsPortName, containerID, podName, podNamespace, containerIface, ips, vlanID)
hostIfAlias := util.VirtualAdapterName(ovsPortName)
// - For containerd runtime, the container interface is created after CNI replying the network setup result.
// So for such case we need to use asynchronous way to wait for interface to be created: we create the OVS port
// and set the OVS Interface type "" first, and change the OVS Interface type to "internal" to connect to the
// container interface after it is created. After OVS connects to the container interface, an OFPort is allocated.
// - For Docker runtime, the container interface is created after antrea-agent attaches the HNSEndpoint to the
// sandbox container, so we create OVS port synchronously.
// - Here antrea-agent determines the way of OVS port creation by checking if container interface is yet created.
// If one day containerd runtime changes the behavior and container interface can be created when attaching
// HNSEndpoint/HostComputeEndpoint, the current implementation will still work. It will choose the synchronized
// way to create OVS port.
if hostInterfaceExistsFunc(hostIfAlias) {
return containerConfig, pc.connectInterfaceToOVSCommon(ovsPortName, netNS, containerConfig)
}
klog.V(2).Infof("Adding OVS port %s for container %s", ovsPortName, containerID)
ovsAttachInfo := BuildOVSPortExternalIDs(containerConfig)
portUUID, err := pc.createOVSPort(ovsPortName, ovsAttachInfo, containerConfig.VLANID)
Expand Down
16 changes: 16 additions & 0 deletions pkg/agent/cniserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,10 @@ func (s *CNIServer) CmdAdd(ctx context.Context, request *cnipb.CniCmdRequest) (*

result := &ipam.IPAMResult{Result: current.Result{CNIVersion: current.ImplementedSpecVersion}}
netNS := s.hostNetNsPath(cniConfig.Netns)
if !validateRuntime(netNS) {
// Support for Docker runtime has been removed since Antrea 2.0.
return nil, fmt.Errorf("failed to process CmdAdd request because Docker runtime is not supported after Antrea 2.0")
}
isInfraContainer := isInfraContainer(netNS)

success := false
Expand Down Expand Up @@ -563,6 +567,12 @@ func (s *CNIServer) CmdDel(ctx context.Context, request *cnipb.CniCmdRequest) (*
return response, nil
}

netNS := s.hostNetNsPath(cniConfig.Netns)
if !validateRuntime(netNS) {
// Support for Docker runtime has been removed since Antrea 2.0.
return nil, fmt.Errorf("failed to process CmdDel request because Docker runtime is not supported after Antrea 2.0")
}

return s.cmdDel(ctx, cniConfig)
}

Expand All @@ -575,6 +585,12 @@ func (s *CNIServer) CmdCheck(_ context.Context, request *cnipb.CniCmdRequest) (
return response, nil
}

netNS := s.hostNetNsPath(cniConfig.Netns)
if !validateRuntime(netNS) {
// Support for Docker runtime has been removed since Antrea 2.0.
return nil, fmt.Errorf("failed to process CmdCheck request because Docker runtime is not supported after Antrea 2.0")
}

infraContainer := cniConfig.getInfraContainer()
s.containerAccess.lockContainer(infraContainer)
defer s.containerAccess.unlockContainer(infraContainer)
Expand Down
6 changes: 6 additions & 0 deletions pkg/agent/cniserver/server_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ func isInfraContainer(netNS string) bool {
return true
}

// validateRuntime returns true if the container runtime is supported by Antrea.
// Always return true on Linux platform, because both Docker and Containerd are supported.
func validateRuntime(netNS string) bool {
return true
}

// getInfraContainer returns the sandbox container ID of a Pod.
// On Linux, it's always the ContainerID in the request.
func (c *CNIConfig) getInfraContainer() string {
Expand Down
6 changes: 6 additions & 0 deletions pkg/agent/cniserver/server_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ func isDockerContainer(netNS string) bool {
return netNS == dockerInfraContainerNetNS || strings.Contains(netNS, ":")
}

// validateRuntime returns false if a container is created by Docker with the provided network namespace
// because the Docker support has been removed since Antrea 2.0.
func validateRuntime(netNS string) bool {
return !isDockerContainer(netNS)
}

func getInfraContainer(containerID, netNS string) string {
if isInfraContainer(netNS) {
return containerID
Expand Down
Loading

0 comments on commit b13bf49

Please sign in to comment.