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
}