func (c *ipamCache) handleIPPoolUpdate(pool calicov3.IPPool, del bool) error {
	c.lock.Lock()
	defer c.lock.Unlock()
	key := pool.Spec.CIDR
	existing := c.ippoolmap[key]
	if del {
		delete(c.ippoolmap, key)
		c.log.Infof("Deleting pool: %s, nat:%t", key, pool.Spec.NATOutgoing)
		return c.ipamUpdateHandler(nil, existing)
	} else if existing != nil && equalPools(&pool, existing) {
		c.log.Infof("Unchanged pool: %s, nat:%t", key, pool.Spec.NATOutgoing)
		return nil
	}
	c.log.Infof("Adding pool: %s, nat:%t", key, pool.Spec.NATOutgoing)
	c.ippoolmap[key] = &pool
	return c.ipamUpdateHandler(&pool, existing)
}
update updates the internal map with IPAM updates when the update
is new addtion to the map or changes the existing item, it calls
ipamUpdateHandler
package watchers
import (
	"net"
	"sync"
	"github.com/pkg/errors"
	calicov3 "github.com/projectcalico/api/pkg/apis/projectcalico/v3"
	"github.com/projectcalico/libcalico-go/lib/options"
	"github.com/projectcalico/libcalico-go/lib/watch"
	"github.com/projectcalico/vpp-dataplane/calico-vpp-agent/routing/common"
	"github.com/sirupsen/logrus"
	"golang.org/x/net/context"
)
func contains(pool *calicov3.IPPool, prefix *net.IPNet) (bool, error) {
	_, poolCIDR, _ := net.ParseCIDR(pool.Spec.CIDR)  
	poolCIDRLen, poolCIDRBits := poolCIDR.Mask.Size()
	prefixLen, prefixBits := prefix.Mask.Size()
	return poolCIDRBits == prefixBits && poolCIDR.Contains(prefix.IP) && prefixLen >= poolCIDRLen, nil
}
func equalPools(a *calicov3.IPPool, b *calicov3.IPPool) bool {
	if a.Spec.CIDR != b.Spec.CIDR {
		return false
	}
	if a.Spec.IPIPMode != b.Spec.IPIPMode {
		return false
	}
	if a.Spec.VXLANMode != b.Spec.VXLANMode {
		return false
	}
	return true
}
type IpamCache interface {
	GetPrefixIPPool(*net.IPNet) *calicov3.IPPool
	SyncIPAM() error
	WaitReady()
	OnVppRestart() error
	IPNetNeedsSNAT(prefix *net.IPNet) bool
}
type ipamCache struct {
	*common.RoutingData
	log       *logrus.Entry
	lock      sync.RWMutex
	ippoolmap map[string]*calicov3.IPPool
	ready     bool
	readyCond *sync.Cond
}
func (c *ipamCache) GetPrefixIPPool(prefix *net.IPNet) *calicov3.IPPool {
	if !c.ready {
		c.readyCond.L.Lock()
		for !c.ready {
			c.readyCond.Wait()
		}
		c.readyCond.L.Unlock()
	}
	c.lock.RLock()
	defer c.lock.RUnlock()
	for _, pool := range c.ippoolmap {
		in, err := contains(pool, prefix)
		if err != nil {
			c.log.Warnf("contains errored: %v", err)
			continue
		}
		if in {
			return pool
		}
	}
	return nil
}
func (c *ipamCache) IPNetNeedsSNAT(prefix *net.IPNet) bool {
	pool := c.GetPrefixIPPool(prefix)
	if pool == nil {
		return false
	} else {
		return pool.Spec.NATOutgoing
	}
}