func()

in network/transparent_vlan_endpointclient_linux.go [209:360]


func (client *TransparentVlanEndpointClient) PopulateVM(epInfo *EndpointInfo) error {
	vmNS, err := client.netnsClient.Get()
	if err != nil {
		return errors.Wrap(err, "failed to get vm ns handle")
	}

	var existingErr error
	client.vnetNSFileDescriptor, existingErr = client.netnsClient.GetFromName(client.vnetNSName)
	// If the ns does not exist, the below code will trigger to create it
	// This will also (we assume) mean the vlan veth does not exist
	if existingErr != nil {
		// We assume the only possible error is that the namespace doesn't exist
		logger.Info("No existing NS detected. Creating the vnet namespace and switching to it", zap.String("message", existingErr.Error()))

		err = RunWithRetries(func() error {
			return client.createNetworkNamespace(vmNS)
		}, numRetries, sleepInMs)
		if err != nil {
			return errors.Wrap(err, "failed to create network namespace")
		}

		deleteNSIfNotNilErr := client.netnsClient.Set(vmNS)
		// Any failure will trigger removing the namespace created
		defer func() {
			if deleteNSIfNotNilErr != nil {
				logger.Info("[transparent vlan] removing vnet ns due to failure...")
				err = client.netnsClient.DeleteNamed(client.vnetNSName)
				if err != nil {
					logger.Error("failed to cleanup/delete ns after failing to create vlan veth")
				}
			}
		}()
		if deleteNSIfNotNilErr != nil {
			return errors.Wrap(deleteNSIfNotNilErr, "failed to set current ns to vm")
		}

		// Now create vlan veth
		logger.Info("Create the host vlan link after getting eth0", zap.String("primaryHostIfName", client.primaryHostIfName))
		// Get parent interface index. Index is consistent across libraries.
		eth0, deleteNSIfNotNilErr := client.netioshim.GetNetworkInterfaceByName(client.primaryHostIfName)
		if deleteNSIfNotNilErr != nil {
			return errors.Wrap(deleteNSIfNotNilErr, "failed to get eth0 interface")
		}
		linkAttrs := vishnetlink.NewLinkAttrs()
		linkAttrs.Name = client.vlanIfName
		// Set the peer
		linkAttrs.ParentIndex = eth0.Index
		link := &vishnetlink.Vlan{
			LinkAttrs: linkAttrs,
			VlanId:    client.vlanID,
		}
		logger.Info("Attempting to create link in VM NS", zap.String("vlanIfName", client.vlanIfName))
		// Create vlan veth
		deleteNSIfNotNilErr = vishnetlink.LinkAdd(link)
		if deleteNSIfNotNilErr != nil {
			// ignore link already exists error
			if !strings.Contains(deleteNSIfNotNilErr.Error(), "file exists") {
				// Any failure to add the link should error (auto delete NS)
				return errors.Wrap(deleteNSIfNotNilErr, "failed to create vlan vnet link after making new ns")
			}
			// Prevent accidentally deleting NS and vlan interface since we ignore this error
			deleteNSIfNotNilErr = nil
		}
		defer func() {
			if deleteNSIfNotNilErr != nil {
				logger.Info("removing vlan veth due to failure...")
				if delErr := client.netlink.DeleteLink(client.vlanIfName); delErr != nil {
					logger.Error("deleting vlan veth failed on addendpoint failure with", zap.Any("error:", delErr.Error()))
				}
			}
		}()

		// sometimes there is slight delay in interface creation. check if it exists
		err = RunWithRetries(func() error {
			_, err = client.netioshim.GetNetworkInterfaceByName(client.vlanIfName)
			return errors.Wrap(err, "failed to get vlan veth")
		}, numRetries, sleepInMs)

		if err != nil {
			deleteNSIfNotNilErr = errors.Wrapf(err, "failed to get vlan veth interface:%s", client.vlanIfName)
			return deleteNSIfNotNilErr
		}

		deleteNSIfNotNilErr = client.netUtilsClient.DisableRAForInterface(client.vlanIfName)
		if deleteNSIfNotNilErr != nil {
			return errors.Wrap(deleteNSIfNotNilErr, "failed to disable router advertisements for vlan vnet link")
		}
		// vlan veth was created successfully, so move the vlan veth you created
		logger.Info("Move vlan link to vnet NS", zap.String("vlanIfName", client.vlanIfName), zap.Any("vnetNSFileDescriptor", uintptr(client.vnetNSFileDescriptor)))
		deleteNSIfNotNilErr = client.setLinkNetNSAndConfirm(client.vlanIfName, uintptr(client.vnetNSFileDescriptor))
		if deleteNSIfNotNilErr != nil {
			return errors.Wrap(deleteNSIfNotNilErr, "failed to move or detect vlan veth inside vnet namespace")
		}
		logger.Info("Moving vlan veth into namespace confirmed")
	} else {
		logger.Info("Existing NS detected. vlan interface should exist or namespace would've been deleted.", zap.String("vnetNSName", client.vnetNSName), zap.String("vlanIfName", client.vlanIfName))
	}

	// Get the default constant host veth mac
	mac, err := net.ParseMAC(defaultHostVethHwAddr)
	if err != nil {
		logger.Info("Failed to parse the mac address", zap.String("defaultHostVethHwAddr", defaultHostVethHwAddr))
	}

	// Create veth pair
	if err = client.netUtilsClient.CreateEndpoint(client.vnetVethName, client.containerVethName, mac); err != nil {
		return errors.Wrap(err, "failed to create veth pair")
	}

	// Ensure vnet veth is created, as there may be a slight delay
	err = RunWithRetries(func() error {
		_, getErr := client.netioshim.GetNetworkInterfaceByName(client.vnetVethName)
		return errors.Wrap(getErr, "failed to get vnet veth")
	}, numRetries, sleepInMs)
	if err != nil {
		return errors.Wrap(err, "vnet veth does not exist")
	}

	// Ensure container veth is created, as there may be a slight delay
	var containerIf *net.Interface
	err = RunWithRetries(func() error {
		var getErr error
		containerIf, getErr = client.netioshim.GetNetworkInterfaceByName(client.containerVethName)
		return errors.Wrap(getErr, "failed to get container veth")
	}, numRetries, sleepInMs)
	if err != nil {
		return errors.Wrap(err, "container veth does not exist")
	}

	// Disable RA for veth pair, and delete if any failure
	if err = client.netUtilsClient.DisableRAForInterface(client.vnetVethName); err != nil {
		if delErr := client.netlink.DeleteLink(client.vnetVethName); delErr != nil {
			logger.Error("Deleting vnet veth failed on addendpoint failure with", zap.Error(delErr))
		}
		return errors.Wrap(err, "failed to disable RA on vnet veth, deleting")
	}
	if err = client.netUtilsClient.DisableRAForInterface(client.containerVethName); err != nil {
		if delErr := client.netlink.DeleteLink(client.containerVethName); delErr != nil {
			logger.Error("Deleting container veth failed on addendpoint failure with", zap.Error(delErr))
		}
		return errors.Wrap(err, "failed to disable RA on container veth, deleting")
	}

	if err = client.setLinkNetNSAndConfirm(client.vnetVethName, uintptr(client.vnetNSFileDescriptor)); err != nil {
		if delErr := client.netlink.DeleteLink(client.vnetVethName); delErr != nil {
			logger.Error("Deleting vnet veth failed on addendpoint failure with", zap.Error(delErr))
		}
		return errors.Wrap(err, "failed to move or detect vnetVethName in vnet ns, deleting")
	}
	client.containerMac = containerIf.HardwareAddr
	return nil
}