func (mnt *MockNatPlugin) ApplyTxn(txn *localclient.Txn, latestRevs *syncbase.PrevRevisions) error {
	mnt.Lock()
	defer mnt.Unlock()
	mnt.Log.Debug("Applying localclient transaction")
	if txn == nil {
		return errors.New("txn is nil")
	}
	if txn.VPPDataChangeTxn != nil || txn.VPPDataResyncTxn != nil {
		return errors.New("vpp txn is not supported")
	}
	if txn.LinuxDataResyncTxn != nil {
		mnt.Reset()
		for key, value := range txn.LinuxDataResyncTxn.Values {
			if key == vpp_nat.GlobalNAT44Key() {
				if err := mnt.putGlobalConfig(value); err != nil {
					return err
				}
			} else if strings.HasPrefix(key, dnat44Prefix) {
				dnatConfig, isDnatConfig := value.(*vpp_nat.DNat44)
				if !isDnatConfig {
					return errors.New("failed to cast DNAT config value")
				}
				newSms, err := mnt.dnatToStaticMappings(dnatConfig)
				if err != nil {
					return err
				}
				if !mnt.staticMappings.Join(newSms) {
					return errors.New("duplicate static mapping")
				}
				newIms, err := mnt.dnatToIdentityMappings(dnatConfig)
				if err != nil {
					return err
				}
				if !mnt.identityMappings.Join(newIms) {
					return errors.New("duplicate identity mapping")
				}
				mnt.nat44Dnat[dnatConfig.Label] = dnatConfig
			} else {
				return errors.New("non-NAT changed in txn")
			}
		}
		return nil
	}
	if txn.LinuxDataChangeTxn == nil {
		return errors.New("linux data change txn is nil")
	}
	dataChange := txn.LinuxDataChangeTxn
	for key, value := range dataChange.Values {
		if key == vpp_nat.GlobalNAT44Key() {
			if value != nil {
				if err := mnt.putGlobalConfig(value); err != nil {
					return err
				}
			} else {
				if mnt.defaultNat44Global {
					return errors.New("cannot remove empty global NAT config")
				}
				mnt.resetNat44Global()
			}
		} else if strings.HasPrefix(key, dnat44Prefix) {
			if value != nil {
				dnatConfig, isDnatConfig := value.(*vpp_nat.DNat44)
				if !isDnatConfig {
					return errors.New("failed to cast DNAT config value")
				}
				prevDnatConfig, modify := mnt.nat44Dnat[dnatConfig.Label]
				if modify {
					oldSms, err := mnt.dnatToStaticMappings(prevDnatConfig)
					if err != nil {
						return err
					}
					mnt.staticMappings.Subtract(oldSms)
					oldIms, err := mnt.dnatToIdentityMappings(prevDnatConfig)
					if err != nil {
						return err
					}
					mnt.identityMappings.Subtract(oldIms)
				}
				newSms, err := mnt.dnatToStaticMappings(dnatConfig)
				if err != nil {
					return err
				}
				if !mnt.staticMappings.Join(newSms) {
					return errors.New("duplicate static mapping")
				}
				newIms, err := mnt.dnatToIdentityMappings(dnatConfig)
				if err != nil {
					return err
				}
				if !mnt.identityMappings.Join(newIms) {
					return errors.New("duplicate identity mapping")
				}
				mnt.nat44Dnat[dnatConfig.Label] = dnatConfig
			} else {
				label := strings.TrimPrefix(key, dnat44Prefix)
				if prevDnatConfig, hasDnat := mnt.nat44Dnat[label]; hasDnat {
					oldSms, err := mnt.dnatToStaticMappings(prevDnatConfig)
					if err != nil {
						return err
					}
					mnt.staticMappings.Subtract(oldSms)
				} else {
					return errors.New("attempt to remove DNAT config which does not exist")
				}
			}
		} else {
			return errors.New("non-NAT changed in txn")
		}
	}
	return nil
}
ApplyTxn applies transaction created by the service configurator.
package natplugin
import (
	"errors"
	"fmt"
	"net"
	"strings"
	"sync"
	"github.com/golang/protobuf/proto"
	"github.com/contiv/vpp/mock/localclient"
	"github.com/contiv/vpp/plugins/service/renderer"
	"go.ligato.io/cn-infra/v2/datasync/syncbase"
	"go.ligato.io/cn-infra/v2/logging"
	vpp_nat "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/nat"
)
const dnat44Prefix = "config/vpp/nat/v2/dnat44/"
type MockNatPlugin struct {
	sync.Mutex
	Log logging.Logger
	defaultNat44Global bool
	nat44Global        *vpp_nat.Nat44Global
	forwarding         bool
	addressPool        []net.IP
	twiceNatPool       []net.IP
	interfaces         map[string]NatFeatures  
	nat44Dnat        map[string]*vpp_nat.DNat44  
	staticMappings   *StaticMappings
	identityMappings *IdentityMappings
}
func NewMockNatPlugin(log logging.Logger) *MockNatPlugin {
	np := &MockNatPlugin{Log: log}
	np.Reset()
	return np
}
func (mnt *MockNatPlugin) resetNat44Global() {
	mnt.defaultNat44Global = true
	mnt.nat44Global = &vpp_nat.Nat44Global{}
	mnt.forwarding = false
	mnt.addressPool = []net.IP{}
	mnt.twiceNatPool = []net.IP{}
	mnt.interfaces = make(map[string]NatFeatures)
}
func (mnt *MockNatPlugin) resetNat44Dnat() {
	mnt.nat44Dnat = make(map[string]*vpp_nat.DNat44)
	mnt.staticMappings = &StaticMappings{}
	mnt.identityMappings = &IdentityMappings{}
}
func (mnt *MockNatPlugin) Reset() {
	mnt.resetNat44Global()
	mnt.resetNat44Dnat()
}