go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/ifplugin/descriptor/interface.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  	context2 "context"
    19  	"fmt"
    20  	"hash/fnv"
    21  	"net"
    22  	"strings"
    23  
    24  	"github.com/pkg/errors"
    25  	"go.ligato.io/cn-infra/v2/idxmap"
    26  	"go.ligato.io/cn-infra/v2/logging"
    27  	"google.golang.org/protobuf/proto"
    28  	empty "google.golang.org/protobuf/types/known/emptypb"
    29  
    30  	kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api"
    31  	linux_ifdescriptor "go.ligato.io/vpp-agent/v3/plugins/linux/ifplugin/descriptor"
    32  	linux_ifaceidx "go.ligato.io/vpp-agent/v3/plugins/linux/ifplugin/ifaceidx"
    33  	"go.ligato.io/vpp-agent/v3/plugins/linux/nsplugin"
    34  	"go.ligato.io/vpp-agent/v3/plugins/netalloc"
    35  	netalloc_descr "go.ligato.io/vpp-agent/v3/plugins/netalloc/descriptor"
    36  	"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/descriptor/adapter"
    37  	"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/ifaceidx"
    38  	"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/vppcalls"
    39  	linux_intf "go.ligato.io/vpp-agent/v3/proto/ligato/linux/interfaces"
    40  	linux_ns "go.ligato.io/vpp-agent/v3/proto/ligato/linux/namespace"
    41  	netalloc_api "go.ligato.io/vpp-agent/v3/proto/ligato/netalloc"
    42  	interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces"
    43  	l3 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l3"
    44  )
    45  
    46  const (
    47  	// InterfaceDescriptorName is the name of the descriptor for VPP interfaces.
    48  	InterfaceDescriptorName = "vpp-interface"
    49  
    50  	// dependency labels
    51  	afPacketHostInterfaceDep = "afpacket-host-interface-exists"
    52  	vxlanMulticastDep        = "vxlan-multicast-interface-exists"
    53  	vxlanVrfTableDep         = "vrf-table-for-vxlan-exists"
    54  	vxlanGpeVrfTableDep      = "vrf-table-for-vxlan-gpe-exists"
    55  	gtpuMulticastDep         = "gtpu-multicast-interface-exists"
    56  	gtpuVrfTableDep          = "vrf-table-for-gtpu-exists"
    57  	ipipVrfTableDep          = "vrf-table-for-ipip-exists"
    58  	microserviceDep          = "microservice-available"
    59  	parentInterfaceDep       = "parent-interface-exists"
    60  	rdmaHostInterfaceDep     = "rdma-host-interface-exists"
    61  
    62  	// how many characters a logical interface name is allowed to have
    63  	//  - determined by much fits into the VPP interface tag (64 null-terminated character string)
    64  	logicalNameLengthLimit = 63
    65  
    66  	// suffix attached to logical names of dumped TAP interfaces with Linux side
    67  	// not found by Retrieve of Linux-ifplugin
    68  	tapMissingLinuxSideSuffix = "-MISSING_LINUX_SIDE"
    69  
    70  	// suffix attached to logical names of dumped AF-PACKET interfaces connected
    71  	// to missing Linux interfaces
    72  	afPacketMissingAttachedIfSuffix = "-MISSING_ATTACHED_INTERFACE"
    73  
    74  	// default memif attributes
    75  	defaultMemifNumOfQueues uint32 = 1
    76  	defaultMemifBufferSize  uint32 = 2048
    77  	defaultMemifRingSize    uint32 = 1024
    78  
    79  	// Length of wireguard private-key in base64. It should be equal 32 in binary
    80  	wireguardKeyLength = 44
    81  
    82  	// default RDMA attributes
    83  	defaultRdmaQueueNum  = 1
    84  	defaultRdmaQueueSize = 1024
    85  )
    86  
    87  // A list of non-retriable errors:
    88  var (
    89  	// ErrUnsupportedVPPInterfaceType is returned for VPP interfaces of unknown type.
    90  	ErrUnsupportedVPPInterfaceType = errors.New("unsupported VPP interface type")
    91  
    92  	// ErrInterfaceWithoutName is returned when VPP interface configuration has undefined
    93  	// Name attribute.
    94  	ErrInterfaceWithoutName = errors.New("VPP interface defined without logical name")
    95  
    96  	// ErrInterfaceNameTooLong is returned when VPP interface logical name exceeds the length limit.
    97  	ErrInterfaceNameTooLong = errors.New("VPP interface logical name exceeds the length limit (63 characters)")
    98  
    99  	// ErrInterfaceWithoutType is returned when VPP interface configuration has undefined
   100  	// Type attribute.
   101  	ErrInterfaceWithoutType = errors.New("VPP interface defined without type")
   102  
   103  	// ErrUnnumberedWithIP is returned when configuration of a VPP unnumbered interface
   104  	// includes an IP address.
   105  	ErrUnnumberedWithIP = errors.New("VPP unnumbered interface was defined with IP address")
   106  
   107  	// ErrAfPacketWithoutTarget is returned when AF-Packet configuration is missing reference to the target linux interface.
   108  	ErrAfPacketWithoutTarget = errors.New(
   109  		"VPP AF-Packet interface was defined without reference to the target linux interface")
   110  
   111  	// ErrInterfaceLinkMismatch is returned when interface type does not match the link configuration.
   112  	ErrInterfaceLinkMismatch = errors.New("VPP interface type and link configuration do not match")
   113  
   114  	// ErrRedefinedRxPlacement is returned when Rx placement has multiple definitions for the same queue.
   115  	ErrRedefinedRxPlacement = errors.New("redefined RX Placement")
   116  
   117  	// ErrSubInterfaceWithoutParent is returned when interface of type sub-interface is defined without parent.
   118  	ErrSubInterfaceWithoutParent = errors.Errorf("subinterface with no parent interface defined")
   119  
   120  	// ErrDPDKInterfaceMissing is returned when the expected DPDK interface does not exist on the VPP.
   121  	ErrDPDKInterfaceMissing = errors.Errorf("DPDK interface with given name does not exists")
   122  
   123  	// ErrBondInterfaceIDExists is returned when the bond interface uses existing ID value
   124  	ErrBondInterfaceIDExists = errors.Errorf("Bond interface ID already exists")
   125  
   126  	// ErrGreBadTunnelType is returned when tunnel type for GRE was not set or set to UNKNOWN
   127  	ErrGreBadTunnelType = errors.Errorf("bad tunnel type for GRE")
   128  
   129  	// ErrGreSrcAddrMissing is returned when source address was not set or set to an empty string.
   130  	ErrGreSrcAddrMissing = errors.Errorf("missing source address for GRE tunnel")
   131  
   132  	// ErrGreDstAddrMissing is returned when destination address was not set or set to an empty string.
   133  	ErrGreDstAddrMissing = errors.Errorf("missing destination address for GRE tunnel")
   134  
   135  	// ErrVxLanGpeBadProtocol is returned when protocol for VxLAN-GPE was not set or set to UNKNOWN.
   136  	ErrVxLanGpeBadProtocol = errors.Errorf("bad protocol for VxLAN-GPE")
   137  
   138  	// ErrVxLanGpeNonZeroDecapVrfID is returned when DecapVrfId was not zero for protocols other than IP4 or IP6.
   139  	ErrVxLanGpeNonZeroDecapVrfID = errors.Errorf("DecapVrfId must be zero for protocols other than IP4 or IP6")
   140  
   141  	// ErrVxLanSrcAddrMissing is returned when source address was not set or set to an empty string.
   142  	ErrVxLanSrcAddrMissing = errors.Errorf("missing source address for VxLAN tunnel")
   143  
   144  	// ErrVxLanDstAddrMissing is returned when destination address was not set or set to an empty string.
   145  	ErrVxLanDstAddrMissing = errors.Errorf("missing destination address for VxLAN tunnel")
   146  
   147  	// ErrVxLanDstAddrBad is returned when destination address was not set to valid IP address.
   148  	ErrVxLanDstAddrBad = errors.Errorf("bad destination address for VxLAN tunnel")
   149  
   150  	// ErrVxLanMulticastIntfMissing is returned when interface for multicast was not specified.
   151  	ErrVxLanMulticastIntfMissing = errors.Errorf("missing multicast interface name for VxLAN tunnel")
   152  
   153  	// ErrGtpuSrcAddrMissing is returned when source address was not set or set to an empty string.
   154  	ErrGtpuSrcAddrMissing = errors.Errorf("missing source address for GTPU tunnel")
   155  
   156  	// ErrGtpuDstAddrMissing is returned when destination address was not set or set to an empty string.
   157  	ErrGtpuDstAddrMissing = errors.Errorf("missing destination address for GTPU tunnel")
   158  
   159  	// ErrGtpuSrcAddrBad is returned when source address was not set to valid IP address.
   160  	ErrGtpuSrcAddrBad = errors.Errorf("bad source address for GTPU tunnel")
   161  
   162  	// ErrGtpuDstAddrBad is returned when destination address was not set to valid IP address.
   163  	ErrGtpuDstAddrBad = errors.Errorf("bad destination address for GTPU tunnel")
   164  
   165  	// ErrIpipSrcAddrMissing is returned when source address was not set or set to an empty string.
   166  	ErrIpipSrcAddrMissing = errors.Errorf("missing source address for IPIP tunnel")
   167  
   168  	// ErrIpipDstAddrMissing is returned when destination address was not set or set to an empty string.
   169  	ErrIpipDstAddrMissing = errors.Errorf("missing destination address for IPIP tunnel")
   170  
   171  	// ErrIpipSrcAddrBad is returned when source address was not set to valid IP address.
   172  	ErrIpipSrcAddrBad = errors.Errorf("bad source address for IPIP tunnel")
   173  
   174  	// ErrIpipDstAddrBad is returned when destination address was not set to valid IP address.
   175  	ErrIpipDstAddrBad = errors.Errorf("bad destination address for IPIP tunnel")
   176  
   177  	// ErrWgKeyLen is returned when private-key length has wrong size.
   178  	ErrWgKeyLen = errors.New("invalid wireguard private-key length")
   179  
   180  	// ErrWgSrcAddrMissing is returned when source address was not set or set to an empty string.
   181  	ErrWgSrcAddrMissing = errors.Errorf("missing source address for wireguard tunnel")
   182  
   183  	// ErrWgSrcAddrBad is returned when source address was not set to valid IP address.
   184  	ErrWgSrcAddrBad = errors.Errorf("bad source address for wireguard tunnel")
   185  
   186  	// ErrWgPort is returned when udp-port exceeds max value.
   187  	ErrWgPort = errors.New("invalid wireguard port")
   188  
   189  	// ErrRdmaHostInterfaceMissing is returned when host_if_name is not configured for RDMA link.
   190  	ErrRdmaHostInterfaceMissing = errors.Errorf("missing the host interface name for RDMA")
   191  
   192  	// ErrRdmaInvalidQueueSize is returned when configured Rx or Tx queue size for RDMA driver is not power of 2.
   193  	ErrRdmaInvalidQueueSize = errors.Errorf("RDMA Rx/Tx queue size is not power of 2")
   194  
   195  	// ErrRdmaQueueSizeTooLarge is returned when configured Rx or Tx queue size for RDMA driver is too large.
   196  	ErrRdmaQueueSizeTooLarge = errors.Errorf("RDMA Rx/Tx queue size is too large (more than 16bits)")
   197  
   198  	// ErrRdmaQueueNumTooLarge is returned when the number of configured Rx/Tx queues for RDMA driver exceeds the limit.
   199  	ErrRdmaQueueNumTooLarge = errors.Errorf("Number of RDMA queues is too large (more than 16bits)")
   200  )
   201  
   202  // InterfaceDescriptor teaches KVScheduler how to configure VPP interfaces.
   203  type InterfaceDescriptor struct {
   204  	// config
   205  	defaultMtu uint32
   206  
   207  	// dependencies
   208  	log       logging.Logger
   209  	ifHandler vppcalls.InterfaceVppAPI
   210  	addrAlloc netalloc.AddressAllocator
   211  
   212  	// optional dependencies, provide if AFPacket and/or TAP+TAP_TO_VPP interfaces are used
   213  	linuxIfPlugin  LinuxPluginAPI
   214  	linuxIfHandler NetlinkAPI
   215  	nsPlugin       nsplugin.API
   216  
   217  	// runtime
   218  	intfIndex              ifaceidx.IfaceMetadataIndex
   219  	memifSocketToID        map[string]uint32 // memif socket filename to ID map (all known sockets)
   220  	defaultMemifSocketPath string
   221  	bondIDs                map[uint32]string // bond ID to name (ID != sw_if_idx)
   222  	ethernetIfs            map[string]uint32 // name-to-index map of ethernet interfaces (entry is not
   223  	// removed even if interface is un-configured)
   224  }
   225  
   226  // LinuxPluginAPI is defined here to avoid import cycles.
   227  type LinuxPluginAPI interface {
   228  	// GetInterfaceIndex gives read-only access to map with metadata of all configured
   229  	// linux interfaces.
   230  	GetInterfaceIndex() linux_ifaceidx.LinuxIfMetadataIndex
   231  }
   232  
   233  // NetlinkAPI here lists only those Netlink methods that are actually used by InterfaceDescriptor.
   234  type NetlinkAPI interface {
   235  	// InterfaceExists verifies interface existence
   236  	InterfaceExists(ifName string) (bool, error)
   237  }
   238  
   239  // NewInterfaceDescriptor creates a new instance of the Interface descriptor.
   240  func NewInterfaceDescriptor(
   241  	ifHandler vppcalls.InterfaceVppAPI,
   242  	addrAlloc netalloc.AddressAllocator,
   243  	defaultMtu uint32,
   244  	linuxIfHandler NetlinkAPI,
   245  	linuxIfPlugin LinuxPluginAPI,
   246  	nsPlugin nsplugin.API,
   247  	log logging.PluginLogger,
   248  ) (*kvs.KVDescriptor, *InterfaceDescriptor) {
   249  	ctx := &InterfaceDescriptor{
   250  		ifHandler:       ifHandler,
   251  		addrAlloc:       addrAlloc,
   252  		defaultMtu:      defaultMtu,
   253  		linuxIfPlugin:   linuxIfPlugin,
   254  		linuxIfHandler:  linuxIfHandler,
   255  		nsPlugin:        nsPlugin,
   256  		log:             log.NewLogger("if-descriptor"),
   257  		memifSocketToID: make(map[string]uint32),
   258  		ethernetIfs:     make(map[string]uint32),
   259  		bondIDs:         make(map[uint32]string),
   260  	}
   261  	typedDescr := &adapter.InterfaceDescriptor{
   262  		Name:               InterfaceDescriptorName,
   263  		NBKeyPrefix:        interfaces.ModelInterface.KeyPrefix(),
   264  		ValueTypeName:      interfaces.ModelInterface.ProtoName(),
   265  		KeySelector:        interfaces.ModelInterface.IsKeyValid,
   266  		KeyLabel:           interfaces.ModelInterface.StripKeyPrefix,
   267  		ValueComparator:    ctx.EquivalentInterfaces,
   268  		WithMetadata:       true,
   269  		MetadataMapFactory: ctx.MetadataFactory,
   270  		Validate:           ctx.Validate,
   271  		Create:             ctx.Create,
   272  		Delete:             ctx.Delete,
   273  		Update:             ctx.Update,
   274  		UpdateWithRecreate: ctx.UpdateWithRecreate,
   275  		Retrieve:           ctx.Retrieve,
   276  		Dependencies:       ctx.Dependencies,
   277  		DerivedValues:      ctx.DerivedValues,
   278  		RetrieveDependencies: []string{
   279  			// refresh the pool of allocated IP addresses first
   280  			netalloc_descr.IPAllocDescriptorName,
   281  			// If Linux-IfPlugin is loaded, dump it first.
   282  			linux_ifdescriptor.InterfaceDescriptorName,
   283  		},
   284  	}
   285  	descr := adapter.NewInterfaceDescriptor(typedDescr)
   286  	return descr, ctx
   287  }
   288  
   289  // SetInterfaceIndex should be used to provide interface index immediately after
   290  // the descriptor registration.
   291  func (d *InterfaceDescriptor) SetInterfaceIndex(intfIndex ifaceidx.IfaceMetadataIndex) {
   292  	d.intfIndex = intfIndex
   293  }
   294  
   295  // EquivalentInterfaces is case-insensitive comparison function for
   296  // interfaces.Interface, also ignoring the order of assigned IP addresses.
   297  func (d *InterfaceDescriptor) EquivalentInterfaces(key string, oldIntf, newIntf *interfaces.Interface) bool {
   298  	// attributes compared as usually:
   299  	if oldIntf.Name != newIntf.Name ||
   300  		oldIntf.Type != newIntf.Type ||
   301  		oldIntf.Enabled != newIntf.Enabled ||
   302  		oldIntf.SetDhcpClient != newIntf.SetDhcpClient {
   303  		return false
   304  	}
   305  	if !proto.Equal(oldIntf.Unnumbered, newIntf.Unnumbered) {
   306  		return false
   307  	}
   308  	if !proto.Equal(oldIntf.Ip6Nd, newIntf.Ip6Nd) {
   309  		return false
   310  	}
   311  
   312  	// type-specific (defaults considered)
   313  	if !d.equivalentTypeSpecificConfig(oldIntf, newIntf) {
   314  		return false
   315  	}
   316  
   317  	if newIntf.Unnumbered == nil { // unnumbered inherits VRF from numbered interface
   318  		if oldIntf.Vrf != newIntf.Vrf {
   319  			return false
   320  		}
   321  	}
   322  
   323  	// handle default/unspecified MTU (except VxLAN and IPSec tunnel)
   324  	if newIntf.Type != interfaces.Interface_VXLAN_TUNNEL && newIntf.Type != interfaces.Interface_IPSEC_TUNNEL {
   325  		if d.getInterfaceMTU(newIntf) != 0 && d.getInterfaceMTU(oldIntf) != d.getInterfaceMTU(newIntf) {
   326  			return false
   327  		}
   328  	}
   329  
   330  	// compare MAC addresses case-insensitively (also handle unspecified MAC address)
   331  	if newIntf.PhysAddress != "" && !strings.EqualFold(oldIntf.PhysAddress, newIntf.PhysAddress) {
   332  		return false
   333  	}
   334  
   335  	if !equalStringSets(oldIntf.IpAddresses, newIntf.IpAddresses) {
   336  		// call Update just to update IP addresses in the metadata
   337  		return false
   338  	}
   339  
   340  	return true
   341  }
   342  
   343  // equivalentTypeSpecificConfig compares type-specific sections of two interface configurations.
   344  func (d *InterfaceDescriptor) equivalentTypeSpecificConfig(oldIntf, newIntf *interfaces.Interface) bool {
   345  	switch oldIntf.Type {
   346  	case interfaces.Interface_TAP:
   347  		if !proto.Equal(getTapConfig(oldIntf), getTapConfig(newIntf)) {
   348  			return false
   349  		}
   350  	case interfaces.Interface_VXLAN_TUNNEL:
   351  		if !proto.Equal(oldIntf.GetVxlan(), newIntf.GetVxlan()) {
   352  			return false
   353  		}
   354  	case interfaces.Interface_AF_PACKET:
   355  		//nolint:staticcheck
   356  		if oldIntf.GetAfpacket().GetHostIfName() != newIntf.GetAfpacket().GetHostIfName() ||
   357  			oldIntf.GetAfpacket().GetLinuxInterface() != newIntf.GetAfpacket().GetLinuxInterface() {
   358  			return false
   359  		}
   360  	case interfaces.Interface_MEMIF:
   361  		if !d.equivalentMemifs(oldIntf.GetMemif(), newIntf.GetMemif()) {
   362  			return false
   363  		}
   364  	case interfaces.Interface_IPSEC_TUNNEL:
   365  		if !d.equivalentIPSecTunnels(oldIntf.GetIpsec(), newIntf.GetIpsec()) {
   366  			return false
   367  		}
   368  	case interfaces.Interface_SUB_INTERFACE:
   369  		if !proto.Equal(oldIntf.GetSub(), newIntf.GetSub()) {
   370  			return false
   371  		}
   372  	case interfaces.Interface_VMXNET3_INTERFACE:
   373  		if !d.equivalentVmxNet3(oldIntf.GetVmxNet3(), newIntf.GetVmxNet3()) {
   374  			return false
   375  		}
   376  	case interfaces.Interface_BOND_INTERFACE:
   377  		if !d.equivalentBond(oldIntf.GetBond(), newIntf.GetBond()) {
   378  			return false
   379  		}
   380  	case interfaces.Interface_GRE_TUNNEL:
   381  		if !proto.Equal(oldIntf.GetGre(), newIntf.GetGre()) {
   382  			return false
   383  		}
   384  	case interfaces.Interface_GTPU_TUNNEL:
   385  		if !proto.Equal(oldIntf.GetGtpu(), newIntf.GetGtpu()) {
   386  			return false
   387  		}
   388  	case interfaces.Interface_IPIP_TUNNEL:
   389  		if !proto.Equal(oldIntf.GetIpip(), newIntf.GetIpip()) {
   390  			return false
   391  		}
   392  	case interfaces.Interface_WIREGUARD_TUNNEL:
   393  		if !proto.Equal(oldIntf.GetWireguard(), newIntf.GetWireguard()) {
   394  			return false
   395  		}
   396  	case interfaces.Interface_RDMA:
   397  		if !d.equivalentRdma(oldIntf.GetRdma(), newIntf.GetRdma()) {
   398  			return false
   399  		}
   400  	}
   401  	return true
   402  }
   403  
   404  // equivalentMemifs compares two memifs for equivalence.
   405  func (d *InterfaceDescriptor) equivalentMemifs(oldMemif, newMemif *interfaces.MemifLink) bool {
   406  	if oldMemif.GetMode() != newMemif.GetMode() ||
   407  		oldMemif.GetMaster() != newMemif.GetMaster() ||
   408  		oldMemif.GetId() != newMemif.GetId() ||
   409  		oldMemif.GetSecret() != newMemif.GetSecret() {
   410  		return false
   411  	}
   412  	// default values considered:
   413  	if d.getMemifSocketFilename(oldMemif) != d.getMemifSocketFilename(newMemif) ||
   414  		d.getMemifBufferSize(oldMemif) != d.getMemifBufferSize(newMemif) ||
   415  		d.getMemifRingSize(oldMemif) != d.getMemifRingSize(newMemif) ||
   416  		d.getMemifNumOfRxQueues(oldMemif) != d.getMemifNumOfRxQueues(newMemif) ||
   417  		d.getMemifNumOfTxQueues(oldMemif) != d.getMemifNumOfTxQueues(newMemif) {
   418  		return false
   419  	}
   420  	return true
   421  }
   422  
   423  // equivalentIPSecTunnels compares two IPSec tunnels for equivalence.
   424  func (d *InterfaceDescriptor) equivalentIPSecTunnels(oldTun, newTun *interfaces.IPSecLink) bool {
   425  	return oldTun.Esn == newTun.Esn &&
   426  		oldTun.AntiReplay == newTun.AntiReplay &&
   427  		oldTun.LocalSpi == newTun.LocalSpi &&
   428  		oldTun.RemoteSpi == newTun.RemoteSpi &&
   429  		oldTun.CryptoAlg == newTun.CryptoAlg &&
   430  		oldTun.LocalCryptoKey == newTun.LocalCryptoKey &&
   431  		oldTun.RemoteCryptoKey == newTun.RemoteCryptoKey &&
   432  		oldTun.IntegAlg == newTun.IntegAlg &&
   433  		oldTun.LocalIntegKey == newTun.LocalIntegKey &&
   434  		oldTun.RemoteIntegKey == newTun.RemoteIntegKey &&
   435  		oldTun.EnableUdpEncap == newTun.EnableUdpEncap
   436  }
   437  
   438  // equivalentVmxNets compares two vmxnet3 interfaces for equivalence.
   439  func (d *InterfaceDescriptor) equivalentVmxNet3(oldVmxNet3, newVmxNet3 *interfaces.VmxNet3Link) bool {
   440  	return oldVmxNet3.RxqSize == newVmxNet3.RxqSize &&
   441  		oldVmxNet3.TxqSize == newVmxNet3.TxqSize
   442  }
   443  
   444  // equivalentBond compares two bond interfaces for equivalence.
   445  func (d *InterfaceDescriptor) equivalentBond(oldBond, newBond *interfaces.BondLink) bool {
   446  	if len(oldBond.BondedInterfaces) != len(newBond.BondedInterfaces) {
   447  		return false
   448  	}
   449  	for _, oldBondSlave := range oldBond.BondedInterfaces {
   450  		var found bool
   451  		for _, newBondSlave := range newBond.BondedInterfaces {
   452  			if oldBondSlave.Name == newBondSlave.Name &&
   453  				oldBondSlave.IsPassive == newBondSlave.IsPassive &&
   454  				oldBondSlave.IsLongTimeout == newBondSlave.IsLongTimeout {
   455  				found = true
   456  			}
   457  		}
   458  		if !found {
   459  			return false
   460  		}
   461  	}
   462  
   463  	return oldBond.Id == newBond.Id &&
   464  		oldBond.Mode == newBond.Mode &&
   465  		oldBond.Lb == newBond.Lb
   466  }
   467  
   468  // equivalentRdma compares two RDMA interfaces for equivalence.
   469  func (d *InterfaceDescriptor) equivalentRdma(oldRdma, newRdma *interfaces.RDMALink) bool {
   470  	return oldRdma.GetHostIfName() == newRdma.GetHostIfName() &&
   471  		oldRdma.GetMode() == newRdma.GetMode() &&
   472  		d.getRdmaQueueNum(oldRdma) == d.getRdmaQueueNum(newRdma) &&
   473  		d.getRdmaRxQueueSize(oldRdma) == d.getRdmaRxQueueSize(newRdma) &&
   474  		d.getRdmaTxQueueSize(oldRdma) == d.getRdmaTxQueueSize(newRdma)
   475  }
   476  
   477  // MetadataFactory is a factory for index-map customized for VPP interfaces.
   478  func (d *InterfaceDescriptor) MetadataFactory() idxmap.NamedMappingRW {
   479  	return ifaceidx.NewIfaceIndex(d.log, "vpp-interface-index")
   480  }
   481  
   482  // Validate validates VPP interface configuration.
   483  func (d *InterfaceDescriptor) Validate(key string, intf *interfaces.Interface) error {
   484  	// validate name
   485  	if name := intf.GetName(); name == "" {
   486  		return kvs.NewInvalidValueError(ErrInterfaceWithoutName, "name")
   487  	} else if len(name) > logicalNameLengthLimit {
   488  		return kvs.NewInvalidValueError(ErrInterfaceNameTooLong, "name")
   489  	}
   490  
   491  	// validate interface type defined
   492  	if intf.GetType() == interfaces.Interface_UNDEFINED_TYPE {
   493  		return kvs.NewInvalidValueError(ErrInterfaceWithoutType, "type")
   494  	}
   495  
   496  	// validate link with interface type
   497  	linkMismatchErr := kvs.NewInvalidValueError(ErrInterfaceLinkMismatch, "link")
   498  	switch intf.GetLink().(type) {
   499  	case *interfaces.Interface_Sub:
   500  		if intf.Type != interfaces.Interface_SUB_INTERFACE {
   501  			return linkMismatchErr
   502  		}
   503  	case *interfaces.Interface_Memif:
   504  		if intf.Type != interfaces.Interface_MEMIF {
   505  			return linkMismatchErr
   506  		}
   507  	case *interfaces.Interface_Afpacket:
   508  		if intf.Type != interfaces.Interface_AF_PACKET {
   509  			return linkMismatchErr
   510  		}
   511  	case *interfaces.Interface_Vxlan:
   512  		if intf.Type != interfaces.Interface_VXLAN_TUNNEL {
   513  			return linkMismatchErr
   514  		}
   515  	case *interfaces.Interface_Tap:
   516  		if intf.Type != interfaces.Interface_TAP {
   517  			return linkMismatchErr
   518  		}
   519  	case *interfaces.Interface_Bond:
   520  		if intf.Type != interfaces.Interface_BOND_INTERFACE {
   521  			return linkMismatchErr
   522  		}
   523  	case *interfaces.Interface_VmxNet3:
   524  		if intf.Type != interfaces.Interface_VMXNET3_INTERFACE {
   525  			return linkMismatchErr
   526  		}
   527  	case *interfaces.Interface_Ipsec:
   528  		if intf.Type != interfaces.Interface_IPSEC_TUNNEL {
   529  			return linkMismatchErr
   530  		}
   531  	case *interfaces.Interface_Gre:
   532  		if intf.Type != interfaces.Interface_GRE_TUNNEL {
   533  			return linkMismatchErr
   534  		}
   535  	case *interfaces.Interface_Gtpu:
   536  		if intf.Type != interfaces.Interface_GTPU_TUNNEL {
   537  			return linkMismatchErr
   538  		}
   539  	case *interfaces.Interface_Ipip:
   540  		if intf.Type != interfaces.Interface_IPIP_TUNNEL {
   541  			return linkMismatchErr
   542  		}
   543  	case *interfaces.Interface_Wireguard:
   544  		if intf.Type != interfaces.Interface_WIREGUARD_TUNNEL {
   545  			return linkMismatchErr
   546  		}
   547  	case *interfaces.Interface_Rdma:
   548  		if intf.Type != interfaces.Interface_RDMA {
   549  			return linkMismatchErr
   550  		}
   551  	case nil:
   552  		if intf.Type != interfaces.Interface_SOFTWARE_LOOPBACK &&
   553  			intf.Type != interfaces.Interface_DPDK {
   554  			return errors.Errorf("VPP interface type %s must have link defined", intf.Type)
   555  		}
   556  	}
   557  
   558  	// validate type specific
   559  	switch intf.GetType() {
   560  	case interfaces.Interface_SUB_INTERFACE:
   561  		if parentName := intf.GetSub().GetParentName(); parentName == "" {
   562  			return kvs.NewInvalidValueError(ErrSubInterfaceWithoutParent, "link.sub.parent_name")
   563  		}
   564  	case interfaces.Interface_DPDK:
   565  		if _, ok := d.ethernetIfs[intf.Name]; !ok {
   566  			return kvs.NewInvalidValueError(ErrDPDKInterfaceMissing, "name")
   567  		}
   568  	case interfaces.Interface_AF_PACKET:
   569  		if intf.GetAfpacket().GetHostIfName() == "" &&
   570  			intf.GetAfpacket().GetLinuxInterface() == "" {
   571  			return kvs.NewInvalidValueError(ErrAfPacketWithoutTarget,
   572  				"link.afpacket.host_if_name", "link.afpacket.linux_interface")
   573  		}
   574  	case interfaces.Interface_BOND_INTERFACE:
   575  		if name, ok := d.bondIDs[intf.GetBond().GetId()]; ok && name != intf.GetName() {
   576  			return kvs.NewInvalidValueError(ErrBondInterfaceIDExists, "link.bond.id")
   577  		}
   578  	case interfaces.Interface_GRE_TUNNEL:
   579  		if intf.GetGre().TunnelType == interfaces.GreLink_UNKNOWN {
   580  			return kvs.NewInvalidValueError(ErrGreBadTunnelType, "link.gre.tunnel_type")
   581  		}
   582  		if intf.GetGre().SrcAddr == "" {
   583  			return kvs.NewInvalidValueError(ErrGreSrcAddrMissing, "link.gre.src_addr")
   584  		}
   585  		if intf.GetGre().DstAddr == "" {
   586  			return kvs.NewInvalidValueError(ErrGreDstAddrMissing, "link.gre.dst_addr")
   587  		}
   588  	case interfaces.Interface_VXLAN_TUNNEL:
   589  		if intf.GetVxlan().SrcAddress == "" {
   590  			return kvs.NewInvalidValueError(ErrVxLanSrcAddrMissing, "link.vxlan.src_address")
   591  		}
   592  		if intf.GetVxlan().DstAddress == "" {
   593  			return kvs.NewInvalidValueError(ErrVxLanDstAddrMissing, "link.vxlan.dst_address")
   594  		}
   595  
   596  		if dst := net.ParseIP(intf.GetVxlan().DstAddress); dst != nil {
   597  			// if destination address is multicast then `Multicast` field must contain interface name.
   598  			if dst.IsMulticast() && intf.GetVxlan().Multicast == "" {
   599  				return kvs.NewInvalidValueError(ErrVxLanMulticastIntfMissing, "link.vxlan.multicast")
   600  			}
   601  		} else {
   602  			// destination address is not valid IP address.
   603  			return kvs.NewInvalidValueError(ErrVxLanDstAddrBad, "link.vxlan.dst_address")
   604  		}
   605  
   606  		if gpe := intf.GetVxlan().Gpe; gpe != nil {
   607  			if gpe.Protocol == interfaces.VxlanLink_Gpe_UNKNOWN {
   608  				return kvs.NewInvalidValueError(ErrVxLanGpeBadProtocol, "link.vxlan.gpe.protocol")
   609  			}
   610  
   611  			// DecapVrfId must be zero if the protocol being encapsulated is not IP4 or IP6.
   612  			isIP46 := gpe.Protocol == interfaces.VxlanLink_Gpe_IP4 || gpe.Protocol == interfaces.VxlanLink_Gpe_IP6
   613  			if !isIP46 && gpe.DecapVrfId != 0 {
   614  				return kvs.NewInvalidValueError(ErrVxLanGpeNonZeroDecapVrfID, "link.vxlan.gpe.decap_vrf_id")
   615  			}
   616  
   617  		}
   618  	case interfaces.Interface_GTPU_TUNNEL:
   619  		if intf.GetGtpu().SrcAddr == "" {
   620  			return kvs.NewInvalidValueError(ErrGtpuSrcAddrMissing, "link.gtpu.src_addr")
   621  		}
   622  		if net.ParseIP(intf.GetGtpu().SrcAddr) == nil {
   623  			return kvs.NewInvalidValueError(ErrGtpuSrcAddrBad, "link.gtpu.src_addr")
   624  		}
   625  
   626  		if intf.GetGtpu().DstAddr == "" {
   627  			return kvs.NewInvalidValueError(ErrGtpuDstAddrMissing, "link.gtpu.dst_addr")
   628  		}
   629  		if net.ParseIP(intf.GetGtpu().DstAddr) == nil {
   630  			return kvs.NewInvalidValueError(ErrGtpuDstAddrBad, "link.gtpu.dst_addr")
   631  		}
   632  	case interfaces.Interface_IPIP_TUNNEL:
   633  		if intf.GetIpip().SrcAddr == "" {
   634  			return kvs.NewInvalidValueError(ErrIpipSrcAddrMissing, "link.ipip.src_addr")
   635  		}
   636  		if net.ParseIP(intf.GetIpip().SrcAddr) == nil {
   637  			return kvs.NewInvalidValueError(ErrIpipSrcAddrBad, "link.ipip.src_addr")
   638  		}
   639  
   640  		if intf.GetIpip().TunnelMode == interfaces.IPIPLink_POINT_TO_POINT {
   641  			if intf.GetIpip().DstAddr == "" {
   642  				return kvs.NewInvalidValueError(ErrIpipDstAddrMissing, "link.ipip.dst_addr")
   643  			}
   644  			if net.ParseIP(intf.GetIpip().DstAddr) == nil {
   645  				return kvs.NewInvalidValueError(ErrIpipDstAddrBad, "link.ipip.dst_addr")
   646  			}
   647  		}
   648  	case interfaces.Interface_WIREGUARD_TUNNEL:
   649  		if intf.GetWireguard().SrcAddr == "" {
   650  			return kvs.NewInvalidValueError(ErrWgSrcAddrMissing, "link.wireguard.src_addr")
   651  		}
   652  		if net.ParseIP(intf.GetWireguard().SrcAddr) == nil {
   653  			return kvs.NewInvalidValueError(ErrWgSrcAddrBad, "link.wireguard.src_addr")
   654  		}
   655  
   656  		if len(intf.GetWireguard().PrivateKey) != wireguardKeyLength {
   657  			return kvs.NewInvalidValueError(ErrWgKeyLen, "link.wireguard.key")
   658  		}
   659  
   660  		if intf.GetWireguard().Port > 0xFFFF {
   661  			return kvs.NewInvalidValueError(ErrWgPort, "link.wireguard.port")
   662  		}
   663  	case interfaces.Interface_RDMA:
   664  		if intf.GetRdma().GetHostIfName() == "" {
   665  			return kvs.NewInvalidValueError(ErrRdmaHostInterfaceMissing, "link.rdma.host_if_name")
   666  		}
   667  		if intf.GetRdma().GetRxqNum()>>16 != 0 {
   668  			return kvs.NewInvalidValueError(ErrRdmaQueueNumTooLarge, "link.rdma.rxq_num")
   669  		}
   670  		if rxQSize := intf.GetRdma().GetRxqSize(); rxQSize > 0 {
   671  			if rxQSize&(rxQSize-1) != 0 {
   672  				return kvs.NewInvalidValueError(ErrRdmaInvalidQueueSize, "link.rdma.rxq_size")
   673  			}
   674  			if rxQSize>>16 != 0 {
   675  				return kvs.NewInvalidValueError(ErrRdmaQueueSizeTooLarge, "link.rdma.rxq_size")
   676  			}
   677  		}
   678  		if txQSize := intf.GetRdma().GetTxqSize(); txQSize > 0 {
   679  			if txQSize&(txQSize-1) != 0 {
   680  				return kvs.NewInvalidValueError(ErrRdmaInvalidQueueSize, "link.rdma.txq_size")
   681  			}
   682  			if txQSize>>16 != 0 {
   683  				return kvs.NewInvalidValueError(ErrRdmaQueueSizeTooLarge, "link.rdma.txq_size")
   684  			}
   685  		}
   686  	}
   687  
   688  	// validate unnumbered
   689  	if intf.GetUnnumbered() != nil {
   690  		if len(intf.GetIpAddresses()) > 0 {
   691  			return kvs.NewInvalidValueError(ErrUnnumberedWithIP, "unnumbered", "ip_addresses")
   692  		}
   693  	}
   694  
   695  	// validate rx placements before before deriving
   696  	for i, rxPlacement1 := range intf.GetRxPlacements() {
   697  		for j := i + 1; j < len(intf.GetRxPlacements()); j++ {
   698  			rxPlacement2 := intf.GetRxPlacements()[j]
   699  			if rxPlacement1.Queue == rxPlacement2.Queue {
   700  				return kvs.NewInvalidValueError(ErrRedefinedRxPlacement,
   701  					fmt.Sprintf("rx_placement[.queue=%d]", rxPlacement1.Queue))
   702  			}
   703  		}
   704  	}
   705  
   706  	return nil
   707  }
   708  
   709  // UpdateWithRecreate returns true if Type or Type-specific attributes are different.
   710  func (d *InterfaceDescriptor) UpdateWithRecreate(key string, oldIntf, newIntf *interfaces.Interface, metadata *ifaceidx.IfaceMetadata) bool {
   711  	if oldIntf.Type != newIntf.Type {
   712  		return true
   713  	}
   714  
   715  	// if type-specific attributes have changed, then re-create the interface
   716  	if !d.equivalentTypeSpecificConfig(oldIntf, newIntf) {
   717  		return true
   718  	}
   719  
   720  	if (oldIntf.GetType() == interfaces.Interface_VXLAN_TUNNEL ||
   721  		oldIntf.GetType() == interfaces.Interface_GTPU_TUNNEL ||
   722  		oldIntf.GetType() == interfaces.Interface_IPIP_TUNNEL) &&
   723  		oldIntf.Vrf != newIntf.Vrf {
   724  		// for VXLAN, GTPU and IPIP interfaces a change in the VRF assignment requires full re-creation
   725  		return true
   726  	}
   727  
   728  	// case for af-packet mac update (cannot be updated directly)
   729  	if oldIntf.GetType() == interfaces.Interface_AF_PACKET && oldIntf.PhysAddress != newIntf.PhysAddress {
   730  		return true
   731  	}
   732  
   733  	return false
   734  }
   735  
   736  // Dependencies lists dependencies for a VPP interface.
   737  func (d *InterfaceDescriptor) Dependencies(key string, intf *interfaces.Interface) (dependencies []kvs.Dependency) {
   738  	switch intf.Type {
   739  	case interfaces.Interface_AF_PACKET:
   740  		// AF-PACKET depends on a referenced Linux interface in the default namespace
   741  		if intf.GetAfpacket().GetLinuxInterface() != "" {
   742  			dependencies = append(dependencies, kvs.Dependency{
   743  				Label: afPacketHostInterfaceDep,
   744  				Key:   linux_intf.InterfaceKey(intf.GetAfpacket().GetLinuxInterface()),
   745  			})
   746  		} else if intf.GetAfpacket().GetHostIfName() != "" {
   747  			dependencies = append(dependencies, kvs.Dependency{
   748  				Label: afPacketHostInterfaceDep,
   749  				Key:   linux_intf.InterfaceHostNameKey(intf.GetAfpacket().GetHostIfName()),
   750  			})
   751  		}
   752  	case interfaces.Interface_TAP:
   753  		// TAP connects VPP with microservice
   754  		if toMicroservice := intf.GetTap().GetToMicroservice(); toMicroservice != "" {
   755  			dependencies = append(dependencies, kvs.Dependency{
   756  				Label: microserviceDep,
   757  				Key:   linux_ns.MicroserviceKey(toMicroservice),
   758  			})
   759  		}
   760  	case interfaces.Interface_VXLAN_TUNNEL:
   761  		// VXLAN referencing an interface with Multicast IP address
   762  		if vxlanMulticast := intf.GetVxlan().GetMulticast(); vxlanMulticast != "" {
   763  			dependencies = append(dependencies, kvs.Dependency{
   764  				Label: vxlanMulticastDep,
   765  				AnyOf: kvs.AnyOfDependency{
   766  					KeyPrefixes: []string{interfaces.InterfaceAddressPrefix(vxlanMulticast)},
   767  					KeySelector: func(key string) bool {
   768  						_, ifaceAddr, source, _, _ := interfaces.ParseInterfaceAddressKey(key)
   769  						if source != netalloc_api.IPAddressSource_ALLOC_REF {
   770  							ip, _, err := net.ParseCIDR(ifaceAddr)
   771  							return err == nil && ip.IsMulticast()
   772  						}
   773  						// TODO: handle the case when multicast IP address is allocated
   774  						// via netalloc (too specific to bother until really needed)
   775  						return false
   776  					},
   777  				},
   778  			})
   779  		}
   780  		if intf.GetVrf() != 0 {
   781  			// binary API for creating VXLAN tunnel requires the VRF table
   782  			// to be already created
   783  			var protocol l3.VrfTable_Protocol
   784  			srcAddr := net.ParseIP(intf.GetVxlan().GetSrcAddress()).To4()
   785  			dstAddr := net.ParseIP(intf.GetVxlan().GetDstAddress()).To4()
   786  			if srcAddr == nil && dstAddr == nil {
   787  				protocol = l3.VrfTable_IPV6
   788  			}
   789  			dependencies = append(dependencies, kvs.Dependency{
   790  				Label: vxlanVrfTableDep,
   791  				Key:   l3.VrfTableKey(intf.GetVrf(), protocol),
   792  			})
   793  		}
   794  
   795  		if gpe := intf.GetVxlan().Gpe; gpe != nil {
   796  			if gpe.DecapVrfId != 0 {
   797  				var protocol l3.VrfTable_Protocol
   798  				if gpe.Protocol == interfaces.VxlanLink_Gpe_IP6 {
   799  					protocol = l3.VrfTable_IPV6
   800  				}
   801  				dependencies = append(dependencies, kvs.Dependency{
   802  					Label: vxlanGpeVrfTableDep,
   803  					Key:   l3.VrfTableKey(gpe.DecapVrfId, protocol),
   804  				})
   805  			}
   806  		}
   807  
   808  	case interfaces.Interface_GTPU_TUNNEL:
   809  		// GTPU referencing an interface with Multicast IP address
   810  		if gtpuMulticast := intf.GetGtpu().GetMulticast(); gtpuMulticast != "" {
   811  			dependencies = append(dependencies, kvs.Dependency{
   812  				Label: gtpuMulticastDep,
   813  				AnyOf: kvs.AnyOfDependency{
   814  					KeyPrefixes: []string{interfaces.InterfaceAddressPrefix(gtpuMulticast)},
   815  					KeySelector: func(key string) bool {
   816  						_, ifaceAddr, source, _, _ := interfaces.ParseInterfaceAddressKey(key)
   817  						if source != netalloc_api.IPAddressSource_ALLOC_REF {
   818  							ip, _, err := net.ParseCIDR(ifaceAddr)
   819  							return err == nil && ip.IsMulticast()
   820  						}
   821  						// TODO: handle the case when multicast IP address is allocated
   822  						// via netalloc (too specific to bother until really needed)
   823  						return false
   824  					},
   825  				},
   826  			})
   827  		}
   828  		if intf.GetGtpu().GetEncapVrfId() != 0 {
   829  			// binary API for creating GTPU tunnel requires the VRF table
   830  			// to be already created
   831  			var protocol l3.VrfTable_Protocol
   832  			srcAddr := net.ParseIP(intf.GetGtpu().GetSrcAddr()).To4()
   833  			dstAddr := net.ParseIP(intf.GetGtpu().GetDstAddr()).To4()
   834  			if srcAddr == nil && dstAddr == nil {
   835  				protocol = l3.VrfTable_IPV6
   836  			}
   837  			dependencies = append(dependencies, kvs.Dependency{
   838  				Label: gtpuVrfTableDep,
   839  				Key:   l3.VrfTableKey(intf.GetGtpu().GetEncapVrfId(), protocol),
   840  			})
   841  		}
   842  
   843  	case interfaces.Interface_IPIP_TUNNEL:
   844  		if intf.GetVrf() != 0 {
   845  			// binary API for creating IPIP tunnel requires the VRF table to be already created
   846  			var protocol l3.VrfTable_Protocol
   847  			srcAddr := net.ParseIP(intf.GetIpip().GetSrcAddr()).To4()
   848  			dstAddr := net.ParseIP(intf.GetIpip().GetDstAddr()).To4()
   849  			if srcAddr == nil && dstAddr == nil {
   850  				protocol = l3.VrfTable_IPV6
   851  			}
   852  			dependencies = append(dependencies, kvs.Dependency{
   853  				Label: ipipVrfTableDep,
   854  				Key:   l3.VrfTableKey(intf.GetVrf(), protocol),
   855  			})
   856  		}
   857  
   858  	case interfaces.Interface_SUB_INTERFACE:
   859  		// SUB_INTERFACE requires parent interface
   860  		if parentName := intf.GetSub().GetParentName(); parentName != "" {
   861  			dependencies = append(dependencies, kvs.Dependency{
   862  				Label: parentInterfaceDep,
   863  				Key:   interfaces.InterfaceKey(parentName),
   864  			})
   865  		}
   866  
   867  	case interfaces.Interface_RDMA:
   868  		// RDMA depends on a referenced Linux interface in the default namespace
   869  		dependencies = append(dependencies, kvs.Dependency{
   870  			Label: rdmaHostInterfaceDep,
   871  			Key:   linux_intf.InterfaceHostNameKey(intf.GetRdma().GetHostIfName()),
   872  		})
   873  	}
   874  
   875  	return dependencies
   876  }
   877  
   878  // DerivedValues derives:
   879  //  - key-value for unnumbered configuration sub-section
   880  //  - empty value for enabled DHCP client
   881  //  - configuration for every slave of a bonded interface
   882  //  - one empty value for every IP address to be assigned to the interface
   883  //  - one empty value for VRF table to put the interface into
   884  //  - one value with interface configuration reduced to RxMode if set
   885  //  - one Interface_RxPlacement for every queue with configured Rx placement
   886  //  - one empty value which will be created once at least one IP address is
   887  //    assigned to the interface.
   888  func (d *InterfaceDescriptor) DerivedValues(key string, intf *interfaces.Interface) (derValues []kvs.KeyValuePair) {
   889  	// unnumbered interface
   890  	if intf.GetUnnumbered() != nil {
   891  		derValues = append(derValues, kvs.KeyValuePair{
   892  			Key:   interfaces.UnnumberedKey(intf.Name),
   893  			Value: intf.GetUnnumbered(),
   894  		})
   895  	}
   896  
   897  	// bond slave interface
   898  	if intf.Type == interfaces.Interface_BOND_INTERFACE && intf.GetBond() != nil {
   899  		for _, slaveIf := range intf.GetBond().GetBondedInterfaces() {
   900  			derValues = append(derValues, kvs.KeyValuePair{
   901  				Key:   interfaces.BondedInterfaceKey(intf.Name, slaveIf.Name),
   902  				Value: slaveIf,
   903  			})
   904  		}
   905  	}
   906  
   907  	// DHCP client
   908  	if intf.SetDhcpClient {
   909  		derValues = append(derValues, kvs.KeyValuePair{
   910  			Key:   interfaces.DHCPClientKey(intf.Name),
   911  			Value: &empty.Empty{},
   912  		})
   913  	}
   914  
   915  	// IP6ND config
   916  	if intf.GetIp6Nd() != nil {
   917  		derValues = append(derValues, kvs.KeyValuePair{
   918  			Key:   interfaces.IP6NDKey(intf.Name),
   919  			Value: intf.GetIp6Nd(),
   920  		})
   921  	}
   922  
   923  	// IP addresses
   924  	for _, ipAddr := range intf.IpAddresses {
   925  		derValues = append(derValues, kvs.KeyValuePair{
   926  			Key:   interfaces.InterfaceAddressKey(intf.Name, ipAddr, netalloc_api.IPAddressSource_STATIC),
   927  			Value: &empty.Empty{},
   928  		})
   929  	}
   930  
   931  	// VRF assignment
   932  	if intf.GetUnnumbered() != nil {
   933  		// VRF inherited from the target numbered interface
   934  		derValues = append(derValues, kvs.KeyValuePair{
   935  			Key:   interfaces.InterfaceInheritedVrfKey(intf.GetName(), intf.GetUnnumbered().GetInterfaceWithIp()),
   936  			Value: &empty.Empty{},
   937  		})
   938  	} else {
   939  		// not unnumbered
   940  		var hasIPv4, hasIPv6 bool
   941  		switch intf.Type {
   942  		case interfaces.Interface_VXLAN_TUNNEL:
   943  			srcAddr := net.ParseIP(intf.GetVxlan().GetSrcAddress()).To4()
   944  			dstAddr := net.ParseIP(intf.GetVxlan().GetDstAddress()).To4()
   945  			if srcAddr == nil && dstAddr == nil {
   946  				hasIPv6 = true
   947  			} else {
   948  				hasIPv4 = true
   949  			}
   950  		case interfaces.Interface_GTPU_TUNNEL:
   951  			srcAddr := net.ParseIP(intf.GetGtpu().GetSrcAddr()).To4()
   952  			dstAddr := net.ParseIP(intf.GetGtpu().GetDstAddr()).To4()
   953  			if srcAddr == nil && dstAddr == nil {
   954  				hasIPv6 = true
   955  			} else {
   956  				hasIPv4 = true
   957  			}
   958  		case interfaces.Interface_IPIP_TUNNEL:
   959  			srcAddr := net.ParseIP(intf.GetIpip().GetSrcAddr()).To4()
   960  			dstAddr := net.ParseIP(intf.GetIpip().GetDstAddr()).To4()
   961  			if srcAddr == nil && dstAddr == nil {
   962  				hasIPv6 = true
   963  			} else {
   964  				hasIPv4 = true
   965  			}
   966  		default:
   967  			hasIPv4, hasIPv6 = getIPAddressVersions(intf.IpAddresses)
   968  		}
   969  		if hasIPv4 || hasIPv6 {
   970  			derValues = append(derValues, kvs.KeyValuePair{
   971  				Key:   interfaces.InterfaceVrfKey(intf.GetName(), int(intf.GetVrf()), hasIPv4, hasIPv6),
   972  				Value: &empty.Empty{},
   973  			})
   974  		}
   975  	}
   976  
   977  	// Rx mode
   978  	if len(intf.GetRxModes()) > 0 {
   979  		derValues = append(derValues, kvs.KeyValuePair{
   980  			Key: interfaces.RxModesKey(intf.GetName()),
   981  			Value: &interfaces.Interface{
   982  				Name:    intf.GetName(),
   983  				Type:    intf.GetType(),
   984  				RxModes: intf.GetRxModes(),
   985  			},
   986  		})
   987  	}
   988  
   989  	// Rx placement
   990  	for _, rxPlacement := range intf.GetRxPlacements() {
   991  		derValues = append(derValues, kvs.KeyValuePair{
   992  			Key:   interfaces.RxPlacementKey(intf.GetName(), rxPlacement.GetQueue()),
   993  			Value: rxPlacement,
   994  		})
   995  	}
   996  
   997  	// with-IP address (property)
   998  	if len(intf.GetIpAddresses()) > 0 {
   999  		derValues = append(derValues, kvs.KeyValuePair{
  1000  			Key:   interfaces.InterfaceWithIPKey(intf.GetName()),
  1001  			Value: &empty.Empty{},
  1002  		})
  1003  	}
  1004  
  1005  	// TODO: define derived value for UP/DOWN state (needed for subinterfaces)
  1006  
  1007  	return derValues
  1008  }
  1009  
  1010  // getInterfaceMTU returns the interface MTU.
  1011  func (d *InterfaceDescriptor) getInterfaceMTU(intf *interfaces.Interface) uint32 {
  1012  	if mtu := intf.GetMtu(); mtu != 0 {
  1013  		return mtu
  1014  	}
  1015  	return d.defaultMtu /* still can be 0, i.e. undefined */
  1016  }
  1017  
  1018  // getAfPacketTargetHostIfName returns the host name of the interface to which the given AF-PACKET
  1019  // interface should bind to.
  1020  //nolint:staticcheck
  1021  func (d *InterfaceDescriptor) getAfPacketTargetHostIfName(afpacket *interfaces.AfpacketLink) (string, error) {
  1022  	if afpacket.GetLinuxInterface() == "" {
  1023  		return afpacket.GetHostIfName(), nil
  1024  	}
  1025  	if d.linuxIfPlugin == nil {
  1026  		return "", errors.New("linux ifplugin dependency is needed for AF-PACKET interface")
  1027  	}
  1028  	linuxIfIdx := d.linuxIfPlugin.GetInterfaceIndex()
  1029  	linuxIfMeta, exists := linuxIfIdx.LookupByName(afpacket.GetLinuxInterface())
  1030  	if !exists {
  1031  		return "", errors.Errorf("failed to find linux interface %s", afpacket.GetLinuxInterface())
  1032  	}
  1033  	return linuxIfMeta.HostIfName, nil
  1034  }
  1035  
  1036  // resolveMemifSocketFilename returns memif socket filename ID.
  1037  // Registers it if does not exists yet.
  1038  func (d *InterfaceDescriptor) resolveMemifSocketFilename(memifIf *interfaces.MemifLink) (uint32, error) {
  1039  	socketFileName := d.getMemifSocketFilename(memifIf)
  1040  	registeredID, registered := d.memifSocketToID[socketFileName]
  1041  	if !registered {
  1042  		// Register new socket. ID is generated (default filename ID is 0, first is ID 1, second ID 2, etc)
  1043  		registeredID = uint32(len(d.memifSocketToID))
  1044  		err := d.ifHandler.RegisterMemifSocketFilename(context2.TODO(), socketFileName, registeredID)
  1045  		if err != nil {
  1046  			return 0, errors.Errorf("error registering socket file name %s (ID %d): %v", socketFileName, registeredID, err)
  1047  		}
  1048  		d.memifSocketToID[socketFileName] = registeredID
  1049  		d.log.Debugf("Memif socket filename %s registered under ID %d", socketFileName, registeredID)
  1050  	}
  1051  	return registeredID, nil
  1052  }
  1053  
  1054  // getMemifSocketFilename returns the memif socket filename.
  1055  func (d *InterfaceDescriptor) getMemifSocketFilename(memif *interfaces.MemifLink) string {
  1056  	if socketFilename := memif.GetSocketFilename(); socketFilename != "" {
  1057  		return socketFilename
  1058  	}
  1059  	return d.defaultMemifSocketPath
  1060  }
  1061  
  1062  // getMemifNumOfRxQueues returns the number of memif RX queues.
  1063  func (d *InterfaceDescriptor) getMemifNumOfRxQueues(memif *interfaces.MemifLink) uint32 {
  1064  	if memif.GetRxQueues() == 0 {
  1065  		return defaultMemifNumOfQueues
  1066  	}
  1067  	return memif.GetRxQueues()
  1068  }
  1069  
  1070  // getMemifNumOfTxQueues returns the number of memif TX queues.
  1071  func (d *InterfaceDescriptor) getMemifNumOfTxQueues(memif *interfaces.MemifLink) uint32 {
  1072  	if memif.GetTxQueues() == 0 {
  1073  		return defaultMemifNumOfQueues
  1074  	}
  1075  	return memif.GetTxQueues()
  1076  }
  1077  
  1078  // getMemifBufferSize returns the memif buffer size.
  1079  func (d *InterfaceDescriptor) getMemifBufferSize(memif *interfaces.MemifLink) uint32 {
  1080  	if memif.GetBufferSize() == 0 {
  1081  		return defaultMemifBufferSize
  1082  	}
  1083  	return memif.GetBufferSize()
  1084  }
  1085  
  1086  // getMemifRingSize returns the memif ring size.
  1087  func (d *InterfaceDescriptor) getMemifRingSize(memif *interfaces.MemifLink) uint32 {
  1088  	if memif.GetRingSize() == 0 {
  1089  		return defaultMemifRingSize
  1090  	}
  1091  	return memif.GetRingSize()
  1092  }
  1093  
  1094  // getRdmaQueueNum returns the number of RDMA queues.
  1095  func (d *InterfaceDescriptor) getRdmaQueueNum(rdma *interfaces.RDMALink) uint32 {
  1096  	if rdma.GetRxqNum() == 0 {
  1097  		return defaultRdmaQueueNum
  1098  	}
  1099  	return rdma.GetRxqNum()
  1100  }
  1101  
  1102  // getRdmaRxQueueSize returns the size of Rx queues of an RDMA interface.
  1103  func (d *InterfaceDescriptor) getRdmaRxQueueSize(rdma *interfaces.RDMALink) uint32 {
  1104  	if rdma.GetRxqSize() == 0 {
  1105  		return defaultRdmaQueueSize
  1106  	}
  1107  	return rdma.GetRxqSize()
  1108  }
  1109  
  1110  // getRdmaTxQueueSize returns the size of Tx queues of an RDMA interface.
  1111  func (d *InterfaceDescriptor) getRdmaTxQueueSize(rdma *interfaces.RDMALink) uint32 {
  1112  	if rdma.GetTxqSize() == 0 {
  1113  		return defaultRdmaQueueSize
  1114  	}
  1115  	return rdma.GetTxqSize()
  1116  }
  1117  
  1118  // getTapConfig returns the TAP-specific configuration section (handling undefined attributes).
  1119  func getTapConfig(intf *interfaces.Interface) (tapLink *interfaces.TapLink) {
  1120  	tapLink = new(interfaces.TapLink)
  1121  	proto.Merge(tapLink, intf.GetTap())
  1122  
  1123  	if tapLink.Version == 0 {
  1124  		tapLink.Version = 1
  1125  	}
  1126  	if tapLink.HostIfName == "" {
  1127  		tapLink.HostIfName = generateTAPHostName(intf.Name)
  1128  	}
  1129  	return tapLink
  1130  }
  1131  
  1132  // generateTAPHostName (deterministically) generates the host name for a TAP interface.
  1133  func generateTAPHostName(tapName string) string {
  1134  	if tapName == "" {
  1135  		return ""
  1136  	}
  1137  	return fmt.Sprintf("tap-%d", fnvHash(tapName))
  1138  }
  1139  
  1140  // fnvHash hashes string using fnv32a algorithm.
  1141  func fnvHash(s string) uint32 {
  1142  	h := fnv.New32a()
  1143  	_, _ = h.Write([]byte(s))
  1144  	return h.Sum32()
  1145  }
  1146  
  1147  // equalStringSets compares two sets of strings for equality.
  1148  func equalStringSets(set1, set2 []string) bool {
  1149  	if len(set1) != len(set2) {
  1150  		return false
  1151  	}
  1152  	for _, item1 := range set1 {
  1153  		found := false
  1154  		for _, item2 := range set2 {
  1155  			if item1 == item2 {
  1156  				found = true
  1157  				break
  1158  			}
  1159  		}
  1160  		if !found {
  1161  			return false
  1162  		}
  1163  	}
  1164  	return true
  1165  }
  1166  
  1167  // getIPAddressVersions returns two flags to tell whether the provided list of addresses
  1168  // contains IPv4 and/or IPv6 type addresses
  1169  func getIPAddressVersions(ipAddrs []string) (hasIPv4, hasIPv6 bool) {
  1170  	for _, ip := range ipAddrs {
  1171  		if strings.HasPrefix(ip, netalloc_api.AllocRefPrefix) {
  1172  			// TODO: figure out how to define VRF-related dependencies with netalloc'd addresses
  1173  			//       - for now assume it is only used with IPv4
  1174  			hasIPv4 = true
  1175  		}
  1176  		if strings.Contains(ip, ":") {
  1177  			hasIPv6 = true
  1178  		} else {
  1179  			hasIPv4 = true
  1180  		}
  1181  	}
  1182  	return
  1183  }