github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/utils/ipprefix/ipprefix.go (about)

     1  package ipprefix
     2  
     3  import (
     4  	"encoding/binary"
     5  	"net"
     6  	"sync"
     7  )
     8  
     9  // FuncOnLpmIP is the type of func which will operate on the value associated with the lpm ip.
    10  type FuncOnLpmIP func(val interface{}) bool
    11  
    12  // FuncOnVals is the type of the func which will operate on each value and will return a new value
    13  // for each associated value.
    14  type FuncOnVals func(val interface{}) interface{}
    15  
    16  //IPcache is an interface which provides functionality to store ip's and do longest prefix match
    17  type IPcache interface {
    18  	// Put takes an argument an ip address, mask and value.
    19  	Put(net.IP, int, interface{})
    20  	// Get takes an argument the IP address and mask and returns the value that is stored for
    21  	// that key.
    22  	Get(net.IP, int) (interface{}, bool)
    23  	// RunFuncOnLpmIP function takes as an argument an IP address and a function. It finds the
    24  	// subnet to which this IP belongs with the longest prefix match. It then calls the
    25  	// function supplied by the user on the value stored and if it succeeds then it returns.
    26  	RunFuncOnLpmIP(net.IP, FuncOnLpmIP)
    27  	// RunFuncOnVals takes an argument a function which is called on all the values stored in
    28  	// the cache. This can be used to update the old values with the new values. If the new
    29  	// value is nil, it will delete the key.
    30  	RunFuncOnVals(FuncOnVals)
    31  }
    32  
    33  const (
    34  	ipv4MaskSize = 32 + 1
    35  	ipv6MaskSize = 128 + 1
    36  )
    37  
    38  type ipcacheV4 struct {
    39  	ipv4 []map[uint32]interface{}
    40  	sync.RWMutex
    41  }
    42  
    43  type ipcacheV6 struct {
    44  	ipv6 []map[[16]byte]interface{}
    45  	sync.RWMutex
    46  }
    47  
    48  type ipcache struct {
    49  	ipv4 *ipcacheV4
    50  	ipv6 *ipcacheV6
    51  }
    52  
    53  func (cache *ipcacheV4) Put(ip net.IP, mask int, val interface{}) {
    54  	cache.Lock()
    55  	defer cache.Unlock()
    56  
    57  	if cache.ipv4[mask] == nil {
    58  		cache.ipv4[mask] = map[uint32]interface{}{}
    59  	}
    60  
    61  	m := cache.ipv4[mask]
    62  	// the following expression is ANDing the ip with the mask
    63  	key := binary.BigEndian.Uint32(ip) & binary.BigEndian.Uint32(net.CIDRMask(mask, 32))
    64  	if val == nil {
    65  		delete(m, key)
    66  	} else {
    67  		m[key] = val
    68  	}
    69  }
    70  
    71  func (cache *ipcacheV4) Get(ip net.IP, mask int) (interface{}, bool) {
    72  	cache.RLock()
    73  	defer cache.RUnlock()
    74  
    75  	m := cache.ipv4[mask]
    76  	if m != nil {
    77  		val, ok := m[binary.BigEndian.Uint32(ip)&binary.BigEndian.Uint32(net.CIDRMask(mask, 32))]
    78  		if ok {
    79  			return val, true
    80  		}
    81  	}
    82  
    83  	return nil, false
    84  }
    85  
    86  func (cache *ipcacheV4) RunFuncOnLpmIP(ip net.IP, f func(val interface{}) bool) {
    87  	cache.Lock()
    88  	defer cache.Unlock()
    89  
    90  	for i := len(cache.ipv4) - 1; i >= 0; i-- {
    91  		m := cache.ipv4[i]
    92  		if m != nil {
    93  			val, ok := m[binary.BigEndian.Uint32(ip)&binary.BigEndian.Uint32(net.CIDRMask(i, 32))]
    94  			if ok && f(val) {
    95  				return
    96  			}
    97  		}
    98  	}
    99  
   100  }
   101  
   102  func (cache *ipcacheV4) RunFuncOnVals(f func(val interface{}) interface{}) {
   103  	cache.Lock()
   104  	defer cache.Unlock()
   105  
   106  	for mask, m := range cache.ipv4 {
   107  		if m == nil {
   108  			continue
   109  		}
   110  
   111  		for ip, val := range m {
   112  			v := f(val)
   113  			if v == nil {
   114  				delete(m, ip)
   115  				continue
   116  			}
   117  
   118  			m[ip] = v
   119  		}
   120  
   121  		if len(m) == 0 {
   122  			cache.ipv4[mask] = nil
   123  		}
   124  	}
   125  
   126  }
   127  
   128  func (cache *ipcacheV6) Put(ip net.IP, mask int, val interface{}) {
   129  	cache.Lock()
   130  	defer cache.Unlock()
   131  
   132  	if cache.ipv6[mask] == nil {
   133  		cache.ipv6[mask] = map[[16]byte]interface{}{}
   134  	}
   135  
   136  	m := cache.ipv6[mask]
   137  	// the following expression is ANDing the ip with the mask
   138  	var maskip [16]byte
   139  	copy(maskip[:], ip.Mask(net.CIDRMask(mask, 128)))
   140  
   141  	if val == nil {
   142  		delete(m, maskip)
   143  	} else {
   144  		m[maskip] = val
   145  	}
   146  }
   147  
   148  func (cache *ipcacheV6) Get(ip net.IP, mask int) (interface{}, bool) {
   149  	cache.RLock()
   150  	defer cache.RUnlock()
   151  
   152  	m := cache.ipv6[mask]
   153  	if m != nil {
   154  		var maskip [16]byte
   155  		copy(maskip[:], ip.Mask(net.CIDRMask(mask, 128)))
   156  		val, ok := m[maskip]
   157  		if ok {
   158  			return val, true
   159  		}
   160  	}
   161  
   162  	return nil, false
   163  }
   164  
   165  func (cache *ipcacheV6) RunFuncOnLpmIP(ip net.IP, f func(val interface{}) bool) {
   166  	cache.Lock()
   167  	defer cache.Unlock()
   168  
   169  	for i := len(cache.ipv6) - 1; i >= 0; i-- {
   170  		m := cache.ipv6[i]
   171  		if m != nil {
   172  			var maskip [16]byte
   173  			copy(maskip[:], ip.Mask(net.CIDRMask(i, 128)))
   174  			val, ok := m[maskip]
   175  			if ok && f(val) {
   176  				return
   177  			}
   178  		}
   179  	}
   180  }
   181  
   182  func (cache *ipcacheV6) RunFuncOnVals(f func(val interface{}) interface{}) {
   183  	cache.Lock()
   184  	defer cache.Unlock()
   185  
   186  	for mask, m := range cache.ipv6 {
   187  		if m == nil {
   188  			continue
   189  		}
   190  
   191  		for ip, val := range m {
   192  			v := f(val)
   193  			if v == nil {
   194  				delete(m, ip)
   195  				continue
   196  			}
   197  
   198  			m[ip] = v
   199  		}
   200  
   201  		if len(m) == 0 {
   202  			cache.ipv6[mask] = nil
   203  		}
   204  	}
   205  }
   206  
   207  //NewIPCache creates an object which is implementing the interface IPcache
   208  func NewIPCache() IPcache {
   209  	return &ipcache{
   210  		ipv4: &ipcacheV4{ipv4: make([]map[uint32]interface{}, ipv4MaskSize)},
   211  		ipv6: &ipcacheV6{ipv6: make([]map[[16]byte]interface{}, ipv6MaskSize)},
   212  	}
   213  }
   214  
   215  func (cache *ipcache) Put(ip net.IP, mask int, val interface{}) {
   216  	if ip.To4() != nil {
   217  		cache.ipv4.Put(ip.To4(), mask, val)
   218  		return
   219  	}
   220  
   221  	cache.ipv6.Put(ip.To16(), mask, val)
   222  }
   223  
   224  func (cache *ipcache) Get(ip net.IP, mask int) (interface{}, bool) {
   225  
   226  	if ip.To4() != nil {
   227  		return cache.ipv4.Get(ip.To4(), mask)
   228  	}
   229  
   230  	return cache.ipv6.Get(ip.To16(), mask)
   231  }
   232  
   233  func (cache *ipcache) RunFuncOnLpmIP(ip net.IP, f FuncOnLpmIP) {
   234  	if ip.To4() != nil {
   235  		cache.ipv4.RunFuncOnLpmIP(ip.To4(), f)
   236  		return
   237  	}
   238  
   239  	cache.ipv6.RunFuncOnLpmIP(ip.To16(), f)
   240  }
   241  
   242  func (cache *ipcache) RunFuncOnVals(f FuncOnVals) {
   243  
   244  	cache.ipv4.RunFuncOnVals(f)
   245  	cache.ipv6.RunFuncOnVals(f)
   246  }