func()

in plugins/vpc-branch-eni/plugin/commands.go [42:182]


func (plugin *Plugin) Add(args *cniSkel.CmdArgs) error {
	// Parse network configuration.
	netConfig, err := config.New(args)
	if err != nil {
		log.Errorf("Failed to parse netconfig from args: %v.", err)
		return err
	}

	log.Infof("Executing ADD with netconfig: %+v.", netConfig)

	// Find the network namespace.
	log.Infof("Searching for netns %s.", args.Netns)
	ns, err := netns.GetNetNS(args.Netns)
	if err != nil {
		log.Errorf("Failed to find netns %s: %v.", args.Netns, err)
		return err
	}

	// Create the trunk ENI.
	trunk, err := eni.NewTrunk(netConfig.TrunkName, netConfig.TrunkMACAddress, eni.TrunkIsolationModeVLAN)
	if err != nil {
		log.Errorf("Failed to find trunk interface %s: %v.", netConfig.TrunkName, err)
		return err
	}

	// Bring up the trunk ENI.
	err = trunk.SetOpState(true)
	if err != nil {
		log.Errorf("Failed to bring up trunk interface %s: %v", netConfig.TrunkName, err)
		return err
	}

	// Create the branch ENI.
	branchName := fmt.Sprintf(branchLinkNameFormat, trunk.GetLinkName(), netConfig.BranchVlanID)
	branch, err := eni.NewBranch(trunk, branchName, netConfig.BranchMACAddress, netConfig.BranchVlanID)
	if err != nil {
		log.Errorf("Failed to create branch interface %s: %v.", branchName, err)
		return err
	}

	// Create a link for the branch ENI.
	log.Infof("Creating branch link %s.", branchName)
	overrideMAC := netConfig.InterfaceType == config.IfTypeVLAN
	err = branch.AttachToLink(overrideMAC)
	if err != nil {
		if os.IsExist(err) {
			// If the branch link already exists, it may have been created in a previous invocation
			// of this plugin. Look for it in the target network namespace and reset it.
			err = ns.Run(func() error {
				err := branch.ENI.AttachToLink()
				if err != nil {
					return err
				}

				for _, ipAddr := range netConfig.IPAddresses {
					err = branch.DeleteIPAddress(&ipAddr)
					if os.IsNotExist(err) {
						err = nil
					} else if err != nil {
						log.Errorf("Failed to reset branch link: %v", err)
					}
				}
				return err
			})
		}
		if err != nil {
			log.Errorf("Failed to attach branch interface %s: %v.", branchName, err)
			return err
		}
	} else {
		// Move branch ENI to the network namespace.
		log.Infof("Moving branch link %s to netns %s.", branch, args.Netns)
		err = branch.SetNetNS(ns)
		if err != nil {
			log.Errorf("Failed to move branch link: %v.", err)
			return err
		}
	}

	// Complete the remaining setup in target network namespace.
	err = ns.Run(func() error {
		var err error

		// Create the container-facing link based on the requested interface type.
		switch netConfig.InterfaceType {
		case config.IfTypeVLAN:
			// Container is running in a network namespace on this host.
			err = plugin.createVLANLink(branch, args.IfName, netConfig.IPAddresses, netConfig.GatewayIPAddresses)
		case config.IfTypeTAP:
			// Container is running in a VM.
			// Connect the branch ENI to a TAP link in the target network namespace.
			bridgeName := fmt.Sprintf(bridgeNameFormat, netConfig.BranchVlanID)
			err = plugin.createTAPLink(branch, bridgeName, args.IfName, netConfig.Tap)
		case config.IfTypeMACVTAP:
			// Container is running in a VM.
			// Connect the branch ENI to a MACVTAP link in the target network namespace.
			err = plugin.createMACVTAPLink(args.IfName, branch.GetLinkIndex())
		}

		// Add a blackhole route for IMDS endpoint if required.
		if netConfig.BlockIMDS {
			err = imds.BlockInstanceMetadataEndpoint()
			if err != nil {
				return err
			}
		}

		// Set branch link operational state up. VLAN interfaces were already brought up above.
		if netConfig.InterfaceType != config.IfTypeVLAN && err == nil {
			log.Infof("Setting branch link state up.")
			err = branch.SetOpState(true)
			if err != nil {
				log.Errorf("Failed to set branch link %v state: %v.", branch, err)
				return err
			}
		}

		return err
	})

	if err != nil {
		log.Errorf("Failed to setup the link: %v.", err)
		return err
	}

	// Generate CNI result.
	// IP addresses, routes and DNS are configured by VPC DHCP servers.
	result := &cniTypesCurrent.Result{
		Interfaces: []*cniTypesCurrent.Interface{
			{
				Name:    args.IfName,
				Mac:     netConfig.BranchMACAddress.String(),
				Sandbox: args.Netns,
			},
		},
	}

	log.Infof("Writing CNI result to stdout: %+v", result)

	return cniTypes.PrintResult(result, netConfig.CNIVersion)
}