go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/l3plugin/descriptor/proxy_arp.go (about)

     1  //  Copyright (c) 2020 Cisco and/or its affiliates.
     2  //
     3  //  Licensed under the Apache License, Version 2.0 (the "License");
     4  //  you may not use this file except in compliance with the License.
     5  //  You may obtain a copy of the License at:
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  //  Unless required by applicable law or agreed to in writing, software
    10  //  distributed under the License is distributed on an "AS IS" BASIS,
    11  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  //  See the License for the specific language governing permissions and
    13  //  limitations under the License.
    14  
    15  package descriptor
    16  
    17  import (
    18  	"net"
    19  	"strings"
    20  
    21  	"github.com/pkg/errors"
    22  	"go.ligato.io/cn-infra/v2/logging"
    23  
    24  	"go.ligato.io/vpp-agent/v3/pkg/models"
    25  	kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api"
    26  	ifdescriptor "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/descriptor"
    27  	"go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/descriptor/adapter"
    28  	"go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/vppcalls"
    29  	l3 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l3"
    30  )
    31  
    32  const (
    33  	// ProxyArpDescriptorName is the name of the descriptor.
    34  	ProxyArpDescriptorName = "vpp-proxy-arp"
    35  
    36  	// Dependency labels:
    37  	vrfTableProxyARPDep = "vrf-table-exists"
    38  )
    39  
    40  // Validation errors:
    41  var (
    42  	// ErrMissingIP returned when one of IP fields in ProxyARP range is not set.
    43  	ErrMissingIP = errors.New("missing IP address")
    44  	// ErrIPWithMask returned when one of IP fields in ProxyARP range is set with a subnet mask.
    45  	ErrIPWithMask = errors.New("only one IP must be defined (e.g. \"192.0.2.1\"), not a subnet")
    46  	// ErrInvalidIP returned when one of IP fields in ProxyARP range can not be parsed.
    47  	ErrInvalidIP = errors.New("invalid IP address")
    48  	// ErrIPv6NotSupported returned when one of IP fields in ProxyARP range is defined as IPv6.
    49  	ErrIPv6NotSupported = errors.New("IP address must be IPv4, not IPv6")
    50  )
    51  
    52  // ProxyArpDescriptor teaches KVScheduler how to configure VPP proxy ARPs.
    53  type ProxyArpDescriptor struct {
    54  	log             logging.Logger
    55  	proxyArpHandler vppcalls.ProxyArpVppAPI
    56  	scheduler       kvs.KVScheduler
    57  }
    58  
    59  // NewProxyArpDescriptor creates a new instance of the ProxyArpDescriptor.
    60  func NewProxyArpDescriptor(scheduler kvs.KVScheduler,
    61  	proxyArpHandler vppcalls.ProxyArpVppAPI, log logging.PluginLogger) *kvs.KVDescriptor {
    62  
    63  	ctx := &ProxyArpDescriptor{
    64  		scheduler:       scheduler,
    65  		proxyArpHandler: proxyArpHandler,
    66  		log:             log.NewLogger("proxy-arp-descriptor"),
    67  	}
    68  
    69  	typedDescr := &adapter.ProxyARPDescriptor{
    70  		Name:                 ProxyArpDescriptorName,
    71  		NBKeyPrefix:          l3.ModelProxyARP.KeyPrefix(),
    72  		ValueTypeName:        l3.ModelProxyARP.ProtoName(),
    73  		KeySelector:          l3.ModelProxyARP.IsKeyValid,
    74  		ValueComparator:      ctx.EquivalentProxyArps,
    75  		Validate:             ctx.Validate,
    76  		Create:               ctx.Create,
    77  		Update:               ctx.Update,
    78  		Delete:               ctx.Delete,
    79  		Retrieve:             ctx.Retrieve,
    80  		Dependencies:         ctx.Dependencies,
    81  		DerivedValues:        ctx.DerivedValues,
    82  		RetrieveDependencies: []string{ifdescriptor.InterfaceDescriptorName},
    83  	}
    84  	return adapter.NewProxyARPDescriptor(typedDescr)
    85  }
    86  
    87  // Validate validates ProxyARP setup.
    88  func (d *ProxyArpDescriptor) Validate(key string, proxyArp *l3.ProxyARP) error {
    89  	for _, r := range proxyArp.Ranges {
    90  		if r.FirstIpAddr == "" {
    91  			return kvs.NewInvalidValueError(ErrMissingIP, "ranges.first_ip_addr")
    92  		}
    93  		if r.LastIpAddr == "" {
    94  			return kvs.NewInvalidValueError(ErrMissingIP, "ranges.last_ip_addr")
    95  		}
    96  
    97  		if strings.Contains(r.FirstIpAddr, "/") {
    98  			return kvs.NewInvalidValueError(ErrIPWithMask, "ranges.first_ip_addr")
    99  		}
   100  		if strings.Contains(r.LastIpAddr, "/") {
   101  			return kvs.NewInvalidValueError(ErrIPWithMask, "ranges.last_ip_addr")
   102  		}
   103  
   104  		firstIP := net.ParseIP(r.FirstIpAddr)
   105  		if firstIP == nil {
   106  			return kvs.NewInvalidValueError(ErrInvalidIP, "ranges.first_ip_addr")
   107  		}
   108  		lastIP := net.ParseIP(r.LastIpAddr)
   109  		if lastIP == nil {
   110  			return kvs.NewInvalidValueError(ErrInvalidIP, "ranges.last_ip_addr")
   111  		}
   112  
   113  		if firstIP.To4() == nil {
   114  			return kvs.NewInvalidValueError(ErrIPv6NotSupported, "ranges.first_ip_addr")
   115  		}
   116  		if lastIP.To4() == nil {
   117  			return kvs.NewInvalidValueError(ErrIPv6NotSupported, "ranges.last_ip_addr")
   118  		}
   119  	}
   120  	return nil
   121  }
   122  
   123  // Dependencies lists dependencies for a VPP Proxy ARP.
   124  func (d *ProxyArpDescriptor) Dependencies(key string, proxyArp *l3.ProxyARP) []kvs.Dependency {
   125  	var dependencies []kvs.Dependency
   126  
   127  	for _, r := range proxyArp.Ranges {
   128  		if r.VrfId == 0 {
   129  			continue
   130  		}
   131  		dependencies = append(dependencies, kvs.Dependency{
   132  			Label: vrfTableProxyARPDep,
   133  			Key:   l3.VrfTableKey(r.VrfId, l3.VrfTable_IPV4),
   134  		})
   135  	}
   136  
   137  	return dependencies
   138  }
   139  
   140  // DerivedValues derives l3.ProxyARP_Interface for every interface.
   141  func (d *ProxyArpDescriptor) DerivedValues(key string, proxyArp *l3.ProxyARP) (derValues []kvs.KeyValuePair) {
   142  	for _, iface := range proxyArp.Interfaces {
   143  		derValues = append(derValues, kvs.KeyValuePair{
   144  			Key:   l3.ProxyARPInterfaceKey(iface.Name),
   145  			Value: iface,
   146  		})
   147  	}
   148  	return derValues
   149  }
   150  
   151  // EquivalentProxyArps compares VPP Proxy ARPs.
   152  func (d *ProxyArpDescriptor) EquivalentProxyArps(key string, oldValue, newValue *l3.ProxyARP) bool {
   153  	if len(newValue.Ranges) != len(oldValue.Ranges) {
   154  		return false
   155  	}
   156  	toAdd, toDelete := calculateRngDiff(newValue.Ranges, oldValue.Ranges)
   157  	return len(toAdd) == 0 && len(toDelete) == 0
   158  }
   159  
   160  // Create adds VPP Proxy ARP.
   161  func (d *ProxyArpDescriptor) Create(key string, value *l3.ProxyARP) (metadata interface{}, err error) {
   162  	for _, r := range value.Ranges {
   163  		firstIP := net.ParseIP(r.FirstIpAddr).To4()
   164  		lastIP := net.ParseIP(r.LastIpAddr).To4()
   165  
   166  		if err := d.proxyArpHandler.AddProxyArpRange(firstIP, lastIP, r.VrfId); err != nil {
   167  			return nil, errors.Errorf("failed to add proxy ARP address range %s - %s (VRF: %d): %v", firstIP, lastIP, r.VrfId, err)
   168  		}
   169  	}
   170  	return nil, nil
   171  }
   172  
   173  // Update modifies VPP Proxy ARP.
   174  func (d *ProxyArpDescriptor) Update(key string, oldValue, newValue *l3.ProxyARP, oldMetadata interface{}) (newMetadata interface{}, err error) {
   175  	toAdd, toDelete := calculateRngDiff(newValue.Ranges, oldValue.Ranges)
   176  
   177  	for _, r := range toDelete {
   178  		firstIP := net.ParseIP(r.FirstIpAddr).To4()
   179  		lastIP := net.ParseIP(r.LastIpAddr).To4()
   180  
   181  		if err := d.proxyArpHandler.DeleteProxyArpRange(firstIP, lastIP, r.VrfId); err != nil {
   182  			return nil, errors.Errorf("failed to delete proxy ARP address range %s - %s (VRF: %d): %v", firstIP, lastIP, r.VrfId, err)
   183  		}
   184  	}
   185  
   186  	for _, r := range toAdd {
   187  		firstIP := net.ParseIP(r.FirstIpAddr).To4()
   188  		lastIP := net.ParseIP(r.LastIpAddr).To4()
   189  
   190  		if err := d.proxyArpHandler.AddProxyArpRange(firstIP, lastIP, r.VrfId); err != nil {
   191  			return nil, errors.Errorf("failed to add proxy ARP address range %s - %s (VRF: %d): %v", firstIP, lastIP, r.VrfId, err)
   192  		}
   193  	}
   194  
   195  	return nil, nil
   196  }
   197  
   198  // Delete deletes VPP Proxy ARP.
   199  func (d *ProxyArpDescriptor) Delete(key string, value *l3.ProxyARP, metadata interface{}) error {
   200  	for _, r := range value.Ranges {
   201  		firstIP := net.ParseIP(r.FirstIpAddr).To4()
   202  		lastIP := net.ParseIP(r.LastIpAddr).To4()
   203  
   204  		if err := d.proxyArpHandler.DeleteProxyArpRange(firstIP, lastIP, r.VrfId); err != nil {
   205  			return errors.Errorf("failed to delete proxy ARP address range %s - %s (VRF: %d): %v", firstIP, lastIP, r.VrfId, err)
   206  		}
   207  	}
   208  	return nil
   209  }
   210  
   211  // Retrieve returns VPP Proxy ARP configuration.
   212  func (d *ProxyArpDescriptor) Retrieve(correlate []adapter.ProxyARPKVWithMetadata) (
   213  	retrieved []adapter.ProxyARPKVWithMetadata, err error) {
   214  
   215  	// Retrieve VPP configuration
   216  	rangesDetails, err := d.proxyArpHandler.DumpProxyArpRanges()
   217  	if err != nil {
   218  		return nil, err
   219  	}
   220  	ifacesDetails, err := d.proxyArpHandler.DumpProxyArpInterfaces()
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  
   225  	proxyArp := &l3.ProxyARP{}
   226  	for _, rangeDetail := range rangesDetails {
   227  		proxyArp.Ranges = append(proxyArp.Ranges, rangeDetail.Range)
   228  	}
   229  	for _, ifaceDetail := range ifacesDetails {
   230  		proxyArp.Interfaces = append(proxyArp.Interfaces, ifaceDetail.Interface)
   231  	}
   232  
   233  	retrieved = append(retrieved, adapter.ProxyARPKVWithMetadata{
   234  		Key:    models.Key(proxyArp),
   235  		Value:  proxyArp,
   236  		Origin: kvs.UnknownOrigin,
   237  	})
   238  
   239  	return retrieved, nil
   240  }
   241  
   242  // calculateRngDiff calculates difference between old and new ranges.
   243  func calculateRngDiff(newRngs, oldRngs []*l3.ProxyARP_Range) (toAdd, toDelete []*l3.ProxyARP_Range) {
   244  	// Find missing ranges.
   245  	for _, newRng := range newRngs {
   246  		var found bool
   247  		for _, oldRng := range oldRngs {
   248  			if newRng.VrfId == oldRng.VrfId &&
   249  				newRng.FirstIpAddr == oldRng.FirstIpAddr &&
   250  				newRng.LastIpAddr == oldRng.LastIpAddr {
   251  				found = true
   252  				break
   253  			}
   254  		}
   255  		if !found {
   256  			toAdd = append(toAdd, newRng)
   257  		}
   258  	}
   259  	// Find obsolete ranges.
   260  	for _, oldRng := range oldRngs {
   261  		var found bool
   262  		for _, newRng := range newRngs {
   263  			if oldRng.VrfId == newRng.VrfId &&
   264  				oldRng.FirstIpAddr == newRng.FirstIpAddr &&
   265  				oldRng.LastIpAddr == newRng.LastIpAddr {
   266  				found = true
   267  				break
   268  			}
   269  		}
   270  		if !found {
   271  			toDelete = append(toDelete, oldRng)
   272  		}
   273  	}
   274  	return
   275  }