func add()

in cmd/routed-eni-cni-plugin/cni.go [133:320]


func add(args *skel.CmdArgs, cniTypes typeswrapper.CNITYPES, grpcClient grpcwrapper.GRPC,
	rpcClient rpcwrapper.RPC, driverClient driver.NetworkAPIs) error {

	conf, log, err := LoadNetConf(args.StdinData)
	if err != nil {
		return errors.Wrap(err, "add cmd: error loading config from args")
	}

	log.Infof("Received CNI add request: ContainerID(%s) Netns(%s) IfName(%s) Args(%s) Path(%s) argsStdinData(%s)",
		args.ContainerID, args.Netns, args.IfName, args.Args, args.Path, args.StdinData)

	log.Debugf("Prev Result: %v\n", conf.PrevResult)

	var k8sArgs K8sArgs
	if err := cniTypes.LoadArgs(args.Args, &k8sArgs); err != nil {
		log.Errorf("Failed to load k8s config from arg: %v", err)
		return errors.Wrap(err, "add cmd: failed to load k8s config from arg")
	}

	// Derive pod MTU. Note that the value has already been validated.
	mtu := networkutils.GetPodMTU(conf.MTU)
	log.Debugf("MTU value set is %d:", mtu)

	// Set up a connection to the ipamD server.
	conn, err := grpcClient.Dial(ipamdAddress, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Errorf("Failed to connect to backend server for container %s: %v",
			args.ContainerID, err)
		return errors.Wrap(err, "add cmd: failed to connect to backend server")
	}
	defer conn.Close()

	c := rpcClient.NewCNIBackendClient(conn)

	r, err := c.AddNetwork(context.Background(),
		&pb.AddNetworkRequest{
			ClientVersion:              version,
			K8S_POD_NAME:               string(k8sArgs.K8S_POD_NAME),
			K8S_POD_NAMESPACE:          string(k8sArgs.K8S_POD_NAMESPACE),
			K8S_POD_INFRA_CONTAINER_ID: string(k8sArgs.K8S_POD_INFRA_CONTAINER_ID),
			Netns:                      args.Netns,
			ContainerID:                args.ContainerID,
			NetworkName:                conf.Name,
			IfName:                     args.IfName,
		})

	if err != nil {
		log.Errorf("Error received from AddNetwork grpc call for containerID %s: %v", args.ContainerID, err)
		return errors.Wrap(err, "add cmd: Error received from AddNetwork gRPC call")
	}

	if !r.Success {
		log.Errorf("Failed to assign an IP address to container %s",
			args.ContainerID)
		return errors.New("add cmd: failed to assign an IP address to container")
	}

	log.Infof("Received add network response from ipamd for container %s interface %s: %+v",
		args.ContainerID, args.IfName, r)

	// We will let the values in result struct guide us in terms of IP Address Family configured.
	var v4Addr, v6Addr, addr *net.IPNet

	// We don't support dual stack mode currently so it has to be either v4 or v6 mode.
	if r.IPv4Addr != "" {
		v4Addr = &net.IPNet{
			IP:   net.ParseIP(r.IPv4Addr),
			Mask: net.CIDRMask(32, 32),
		}
		addr = v4Addr
	} else if r.IPv6Addr != "" {
		v6Addr = &net.IPNet{
			IP:   net.ParseIP(r.IPv6Addr),
			Mask: net.CIDRMask(128, 128),
		}
		addr = v6Addr
	}
	// AddNetwork guarantees that Gateway string is a valid IPNet
	gw := net.ParseIP(r.PodENISubnetGW)

	var hostVethName string
	var dummyInterface *current.Interface

	// The dummy interface is purely virtual and is stored in the prevResult struct to assist in cleanup during the DEL command.
	dummyInterfaceName := networkutils.GeneratePodHostVethName(dummyInterfacePrefix, string(k8sArgs.K8S_POD_NAMESPACE), string(k8sArgs.K8S_POD_NAME))

	// Non-zero value means pods are using branch ENI
	if r.PodVlanId != 0 {
		hostVethNamePrefix := sgpp.BuildHostVethNamePrefix(conf.VethPrefix, conf.PodSGEnforcingMode)
		hostVethName = networkutils.GeneratePodHostVethName(hostVethNamePrefix, string(k8sArgs.K8S_POD_NAMESPACE), string(k8sArgs.K8S_POD_NAME))
		err = driverClient.SetupBranchENIPodNetwork(hostVethName, args.IfName, args.Netns, v4Addr, v6Addr, int(r.PodVlanId), r.PodENIMAC,
			r.PodENISubnetGW, int(r.ParentIfIndex), mtu, conf.PodSGEnforcingMode, log)
		// For branch ENI mode, the pod VLAN ID is packed in Interface.Mac
		dummyInterface = &current.Interface{Name: dummyInterfaceName, Mac: fmt.Sprint(r.PodVlanId)}
	} else {
		// build hostVethName
		// Note: the maximum length for linux interface name is 15
		hostVethName = networkutils.GeneratePodHostVethName(conf.VethPrefix, string(k8sArgs.K8S_POD_NAMESPACE), string(k8sArgs.K8S_POD_NAME))
		err = driverClient.SetupPodNetwork(hostVethName, args.IfName, args.Netns, v4Addr, v6Addr, int(r.DeviceNumber), mtu, log)
		// For non-branch ENI, the pod VLAN ID value of 0 is packed in Interface.Mac, while the interface device number is packed in Interface.Sandbox
		dummyInterface = &current.Interface{Name: dummyInterfaceName, Mac: fmt.Sprint(0), Sandbox: fmt.Sprint(r.DeviceNumber)}
	}
	log.Debugf("Using dummy interface: %v", dummyInterface)

	if err != nil {
		log.Errorf("Failed SetupPodNetwork for container %s: %v",
			args.ContainerID, err)

		// return allocated IP back to IP pool
		r, delErr := c.DelNetwork(context.Background(), &pb.DelNetworkRequest{
			ClientVersion:              version,
			K8S_POD_NAME:               string(k8sArgs.K8S_POD_NAME),
			K8S_POD_NAMESPACE:          string(k8sArgs.K8S_POD_NAMESPACE),
			K8S_POD_INFRA_CONTAINER_ID: string(k8sArgs.K8S_POD_INFRA_CONTAINER_ID),
			ContainerID:                args.ContainerID,
			IfName:                     args.IfName,
			NetworkName:                conf.Name,
			Reason:                     "SetupNSFailed",
		})

		if delErr != nil {
			log.Errorf("Error received from DelNetwork grpc call for container %s: %v", args.ContainerID, delErr)
		} else if !r.Success {
			log.Errorf("Failed to release IP of container %s", args.ContainerID)
		}
		return errors.Wrap(err, "add command: failed to setup network")
	}

	containerInterfaceIndex := 1
	ips := []*current.IPConfig{
		{
			Interface: &containerInterfaceIndex,
			Address:   *addr,
			Gateway:   gw,
		},
	}

	hostInterface := &current.Interface{Name: hostVethName}
	containerInterface := &current.Interface{Name: args.IfName, Sandbox: args.Netns}

	result := &current.Result{
		IPs: ips,
		Interfaces: []*current.Interface{
			hostInterface,
			containerInterface,
		},
	}

	// dummy interface is appended to PrevResult for use during cleanup
	result.Interfaces = append(result.Interfaces, dummyInterface)

	// Set up a connection to the network policy agent
	// NP container might have been removed if network policies are not being used
	// If NETWORK_POLICY_ENFORCING_MODE is not set, we will not configure anything related to NP
	if r.NetworkPolicyMode == "" {
		log.Infof("NETWORK_POLICY_ENFORCING_MODE is not set")
		return cniTypes.PrintResult(result, conf.CNIVersion)
	}
	ctx, cancel := context.WithTimeout(context.Background(), npAgentConnTimeout*time.Second) // Set timeout
	defer cancel()
	npConn, err := grpcClient.DialContext(ctx, npAgentAddress, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock())
	if err != nil {
		log.Errorf("Failed to connect to network policy agent: %v", err)
		return errors.New("add cmd: failed to setup network policy")
	}
	defer npConn.Close()

	//Make a GRPC call for network policy agent
	npc := rpcClient.NewNPBackendClient(npConn)

	npr, err := npc.EnforceNpToPod(context.Background(),
		&pb.EnforceNpRequest{
			K8S_POD_NAME:        string(k8sArgs.K8S_POD_NAME),
			K8S_POD_NAMESPACE:   string(k8sArgs.K8S_POD_NAMESPACE),
			NETWORK_POLICY_MODE: r.NetworkPolicyMode,
		})

	// No need to cleanup IP and network, kubelet will send delete.
	if err != nil || !npr.Success {
		log.Errorf("Failed to setup default network policy for Pod Name %s and NameSpace %s: GRPC returned - %v Network policy agent returned - %v",
			string(k8sArgs.K8S_POD_NAME), string(k8sArgs.K8S_POD_NAMESPACE), err, npr)
		return errors.New("add cmd: failed to setup network policy")
	}

	log.Debugf("Network Policy agent for EnforceNpToPod returned Success : %v", npr.Success)

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