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

     1  // Copyright (c) 2018 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  	"github.com/pkg/errors"
    19  	"go.ligato.io/cn-infra/v2/logging"
    20  	"google.golang.org/protobuf/proto"
    21  
    22  	kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api"
    23  	"go.ligato.io/vpp-agent/v3/plugins/netalloc"
    24  	"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/ifaceidx"
    25  	"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/vppcalls"
    26  	netalloc_api "go.ligato.io/vpp-agent/v3/proto/ligato/netalloc"
    27  	interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces"
    28  )
    29  
    30  const (
    31  	// InterfaceAddressDescriptorName is the name of the descriptor for assigning
    32  	// IP addresses to VPP interfaces.
    33  	InterfaceAddressDescriptorName = "vpp-interface-address"
    34  
    35  	// dependency labels
    36  	interfaceInVrfDep = "interface-assigned-to-vrf-table"
    37  )
    38  
    39  // InterfaceAddressDescriptor (un)assigns (static) IP address to/from VPP interface.
    40  type InterfaceAddressDescriptor struct {
    41  	log       logging.Logger
    42  	ifHandler vppcalls.InterfaceVppAPI
    43  	ifIndex   ifaceidx.IfaceMetadataIndex
    44  	addrAlloc netalloc.AddressAllocator
    45  }
    46  
    47  // NewInterfaceAddressDescriptor creates a new instance of InterfaceAddressDescriptor.
    48  func NewInterfaceAddressDescriptor(ifHandler vppcalls.InterfaceVppAPI, addrAlloc netalloc.AddressAllocator,
    49  	ifIndex ifaceidx.IfaceMetadataIndex, log logging.PluginLogger) *kvs.KVDescriptor {
    50  
    51  	descrCtx := &InterfaceAddressDescriptor{
    52  		ifHandler: ifHandler,
    53  		ifIndex:   ifIndex,
    54  		addrAlloc: addrAlloc,
    55  		log:       log.NewLogger("interface-address-descriptor"),
    56  	}
    57  	return &kvs.KVDescriptor{
    58  		Name:         InterfaceAddressDescriptorName,
    59  		KeySelector:  descrCtx.IsInterfaceAddressKey,
    60  		Validate:     descrCtx.Validate,
    61  		Create:       descrCtx.Create,
    62  		Delete:       descrCtx.Delete,
    63  		Dependencies: descrCtx.Dependencies,
    64  	}
    65  }
    66  
    67  // IsInterfaceAddressKey returns true if the key represents assignment of an IP address
    68  // to a VPP interface (that needs to be applied). KVs representing addresses
    69  // already allocated from netalloc plugin or obtained from a DHCP server are
    70  // excluded.
    71  func (d *InterfaceAddressDescriptor) IsInterfaceAddressKey(key string) bool {
    72  	_, _, source, _, isAddrKey := interfaces.ParseInterfaceAddressKey(key)
    73  	return isAddrKey &&
    74  		(source == netalloc_api.IPAddressSource_STATIC || source == netalloc_api.IPAddressSource_ALLOC_REF)
    75  }
    76  
    77  // Validate validates IP address to be assigned to an interface.
    78  func (d *InterfaceAddressDescriptor) Validate(key string, emptyVal proto.Message) (err error) {
    79  	iface, addr, _, invalidKey, _ := interfaces.ParseInterfaceAddressKey(key)
    80  	if invalidKey {
    81  		return errors.New("invalid key")
    82  	}
    83  
    84  	return d.addrAlloc.ValidateIPAddress(addr, iface, "ip_addresses", netalloc.GwRefUnexpected)
    85  }
    86  
    87  // Create assigns IP address to an interface.
    88  func (d *InterfaceAddressDescriptor) Create(key string, emptyVal proto.Message) (metadata kvs.Metadata, err error) {
    89  	iface, addr, _, _, _ := interfaces.ParseInterfaceAddressKey(key)
    90  
    91  	ifMeta, found := d.ifIndex.LookupByName(iface)
    92  	if !found {
    93  		err = errors.Errorf("failed to find interface %s", iface)
    94  		d.log.Error(err)
    95  		return nil, err
    96  	}
    97  
    98  	ipAddr, err := d.addrAlloc.GetOrParseIPAddress(addr, iface, netalloc_api.IPAddressForm_ADDR_WITH_MASK)
    99  	if err != nil {
   100  		d.log.Error(err)
   101  		return nil, err
   102  	}
   103  
   104  	err = d.ifHandler.AddInterfaceIP(ifMeta.SwIfIndex, ipAddr)
   105  	return nil, err
   106  }
   107  
   108  // Delete unassigns IP address from an interface.
   109  func (d *InterfaceAddressDescriptor) Delete(key string, emptyVal proto.Message, metadata kvs.Metadata) (err error) {
   110  	iface, addr, _, _, _ := interfaces.ParseInterfaceAddressKey(key)
   111  
   112  	ifMeta, found := d.ifIndex.LookupByName(iface)
   113  	if !found {
   114  		err = errors.Errorf("failed to find interface %s", iface)
   115  		d.log.Error(err)
   116  		return err
   117  	}
   118  
   119  	ipAddr, err := d.addrAlloc.GetOrParseIPAddress(addr, iface, netalloc_api.IPAddressForm_ADDR_WITH_MASK)
   120  	if err != nil {
   121  		d.log.Error(err)
   122  		return err
   123  	}
   124  
   125  	// do not delete (auto-assigned) IPv6 link-local addresses
   126  	if ipAddr.IP.To4() == nil && ipAddr.IP.IsLinkLocalUnicast() {
   127  		return nil
   128  	}
   129  
   130  	err = d.ifHandler.DelInterfaceIP(ifMeta.SwIfIndex, ipAddr)
   131  	return err
   132  }
   133  
   134  // Dependencies lists assignment of the interface into the VRF table and potential
   135  // allocation of the IP address as dependencies.
   136  func (d *InterfaceAddressDescriptor) Dependencies(key string, emptyVal proto.Message) []kvs.Dependency {
   137  	iface, addr, _, _, _ := interfaces.ParseInterfaceAddressKey(key)
   138  	deps := []kvs.Dependency{{
   139  		Label: interfaceInVrfDep,
   140  		AnyOf: kvs.AnyOfDependency{
   141  			KeyPrefixes: []string{interfaces.InterfaceVrfKeyPrefix(iface)},
   142  		},
   143  	}}
   144  
   145  	allocDep, hasAllocDep := d.addrAlloc.GetAddressAllocDep(addr, iface, "")
   146  	if hasAllocDep {
   147  		deps = append(deps, allocDep)
   148  	}
   149  
   150  	return deps
   151  }