func()

in npm/pkg/controlplane/controllers/v1/networkPolicyController.go [325:422]


func (c *NetworkPolicyController) syncAddAndUpdateNetPol(netPolObj *networkingv1.NetworkPolicy) (metrics.OperationKind, error) {
	var err error
	netpolKey, err := cache.MetaNamespaceKeyFunc(netPolObj)
	if err != nil {
		// consider a no-op since we can't determine add vs. update. The exec time here isn't important either.
		return metrics.NoOp, fmt.Errorf("[syncAddAndUpdateNetPol] Error: while running MetaNamespaceKeyFunc err: %w", err)
	}

	// Start reconciling loop to eventually meet cached states against the desired states from network policy.
	// #1 If a new network policy is created, the network policy is not in RawNPMap.
	// start translating policy and install translated ipset and iptables rules into kernel
	// #2 If a network policy with <ns>-<netpol namespace>-<netpol name> is applied before and two network policy are the same object (same UID),
	// first delete the applied network policy, then start translating policy and install translated ipset and iptables rules into kernel
	// #3 If a network policy with <ns>-<netpol namespace>-<netpol name> is applied before and two network policy are the different object (different UID) due to missing some events for the old object
	// first delete the applied network policy, then start translating policy and install translated ipset and iptables rules into kernel
	// To deal with all three cases, we first delete network policy if possible, then install translated rules into kernel.
	// (TODO): can optimize logic more to reduce computations. For example, apply only difference if possible like podController

	// Do not need to clean up default Azure NPM chain in deleteNetworkPolicy function, if network policy object is applied soon.
	// So, avoid extra overhead to install default Azure NPM chain in initializeDefaultAzureNpmChain function.
	// To achieve it, use flag unSafeToCleanUpAzureNpmChain to indicate that the default Azure NPM chain cannot be deleted.
	// delete existing network policy

	var operationKind metrics.OperationKind
	if _, ok := c.rawNpMap[netpolKey]; ok {
		operationKind = metrics.UpdateOp
	} else {
		operationKind = metrics.CreateOp
	}

	err = c.cleanUpNetworkPolicy(netpolKey, unSafeToCleanUpAzureNpmChain)
	if err != nil {
		return operationKind, fmt.Errorf("[syncAddAndUpdateNetPol] Error: failed to deleteNetworkPolicy due to %w", err)
	}

	// Install this default rules for kube-system and azure-npm chains if they are not initilized.
	// Execute initializeDefaultAzureNpmChain function first before actually starting processing network policy object.
	if err = c.initializeDefaultAzureNpmChain(); err != nil {
		return operationKind, fmt.Errorf("[syncNetPol] Error: due to %w", err)
	}

	// Cache network object first before applying ipsets and iptables.
	// If error happens while applying ipsets and iptables,
	// the key is re-queued in workqueue and process this function again, which eventually meets desired states of network policy
	c.rawNpMap[netpolKey] = netPolObj
	metrics.IncNumPolicies()
	c.ipsMgr.Lock()
	defer c.ipsMgr.Unlock()

	sets, namedPorts, lists, ingressIPCidrs, egressIPCidrs, iptEntries := translatePolicy(netPolObj)
	for _, set := range sets {
		klog.Infof("Creating set: %v, hashedSet: %v", set, util.GetHashedName(set))
		if err = c.ipsMgr.CreateSetNoLock(set, []string{util.IpsetNetHashFlag}); err != nil {
			return operationKind, fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset %s with err: %w", set, err)
		}
	}
	for _, set := range namedPorts {
		klog.Infof("Creating set: %v, hashedSet: %v", set, util.GetHashedName(set))
		if err = c.ipsMgr.CreateSetNoLock(set, []string{util.IpsetIPPortHashFlag}); err != nil {
			return operationKind, fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset named port %s with err: %w", set, err)
		}
	}

	// lists is a map with list name and members as value
	// NPM will create the list first and increments the refer count
	for listKey := range lists {
		if err = c.ipsMgr.CreateListNoLock(listKey); err != nil {
			return operationKind, fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset list %s with err: %w", listKey, err)
		}
		c.ipsMgr.IpSetReferIncOrDec(listKey, util.IpsetSetListFlag, ipsm.IncrementOp)
	}
	// Then NPM will add members to the above list, this is to avoid members being added
	// to lists before they are created.
	for listKey, listLabelsMembers := range lists {
		for _, listMember := range listLabelsMembers {
			if err = c.ipsMgr.AddToListNoLock(listKey, listMember); err != nil {
				return operationKind, fmt.Errorf("[syncAddAndUpdateNetPol] Error: Adding ipset member %s to ipset list %s with err: %w", listMember, listKey, err)
			}
		}
		c.ipsMgr.IpSetReferIncOrDec(listKey, util.IpsetSetListFlag, ipsm.IncrementOp)
	}

	if err = c.createCidrsRule("in", netPolObj.Name, netPolObj.Namespace, ingressIPCidrs); err != nil {
		return operationKind, fmt.Errorf("[syncAddAndUpdateNetPol] Error: createCidrsRule in due to %w", err)
	}

	if err = c.createCidrsRule("out", netPolObj.Name, netPolObj.Namespace, egressIPCidrs); err != nil {
		return operationKind, fmt.Errorf("[syncAddAndUpdateNetPol] Error: createCidrsRule out due to %w", err)
	}

	for _, iptEntry := range iptEntries {
		if err = c.iptMgr.Add(iptEntry); err != nil {
			return operationKind, fmt.Errorf("[syncAddAndUpdateNetPol] Error: failed to apply iptables rule. Rule: %+v with err: %w", iptEntry, err)
		}
	}

	return operationKind, nil
}