go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/ifplugin/ifaceidx/ifaceidx.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 ifaceidx
    16  
    17  import (
    18  	"time"
    19  
    20  	"go.ligato.io/cn-infra/v2/idxmap"
    21  	"go.ligato.io/cn-infra/v2/logging"
    22  
    23  	"go.ligato.io/vpp-agent/v3/pkg/idxvpp"
    24  )
    25  
    26  // IfaceMetadataIndex provides read-only access to mapping with VPP interface
    27  // metadata. It extends from NameToIndex.
    28  type IfaceMetadataIndex interface {
    29  	// LookupByName retrieves a previously stored metadata of interface
    30  	// identified by <name>. If there is no interface associated with the give
    31  	// name in the mapping, the <exists> is returned as *false* and <metadata>
    32  	// as *nil*.
    33  	LookupByName(name string) (metadata *IfaceMetadata, exists bool)
    34  
    35  	// LookupBySwIfIndex retrieves a previously stored interface identified in
    36  	// VPP by the given <swIfIndex>.
    37  	// If there is no interface associated with the given index, <exists> is returned
    38  	// as *false* with <name> and <metadata> both set to empty values.
    39  	LookupBySwIfIndex(swIfIndex uint32) (name string, metadata *IfaceMetadata, exists bool)
    40  
    41  	// LookupByIP returns a list of interfaces that have the given IP address
    42  	// assigned.
    43  	LookupByIP(ip string) []string /* name */
    44  
    45  	// ListAllInterfaces returns slice of names of all interfaces in the mapping.
    46  	ListAllInterfaces() (names []string)
    47  
    48  	// WatchInterfaces allows to subscribe to watch for changes in the mapping
    49  	// if interface metadata.
    50  	WatchInterfaces(subscriber string, channel chan<- IfaceMetadataDto)
    51  }
    52  
    53  // IfaceMetadataIndexRW provides read-write access to mapping with interface
    54  // metadata.
    55  type IfaceMetadataIndexRW interface {
    56  	IfaceMetadataIndex
    57  	idxmap.NamedMappingRW
    58  }
    59  
    60  // IfaceMetadata collects metadata for VPP interface used in secondary lookups.
    61  type IfaceMetadata struct {
    62  	SwIfIndex     uint32
    63  	Vrf           uint32
    64  	IPAddresses   []string // TODO: update from interfaceAddress descriptor with real IPs (not netalloc links)
    65  	TAPHostIfName string   /* host interface name set for the Linux-side of the TAP interface; empty for non-TAPs */
    66  	InternalName  string   // internal VPP name
    67  	DevType       string   // device type
    68  }
    69  
    70  // GetIndex returns sw_if_index assigned to the interface.
    71  func (ifm *IfaceMetadata) GetIndex() uint32 {
    72  	return ifm.SwIfIndex
    73  }
    74  
    75  // IfaceMetadataDto represents an item sent through watch channel in IfaceMetadataIndex.
    76  // In contrast to NamedMappingGenericEvent, it contains typed interface metadata.
    77  type IfaceMetadataDto struct {
    78  	idxmap.NamedMappingEvent
    79  	Metadata *IfaceMetadata
    80  }
    81  
    82  // ifaceMetadataIndex is type-safe implementation of mapping between interface
    83  // name and metadata of type *InterfaceMeta.
    84  type ifaceMetadataIndex struct {
    85  	idxmap.NamedMappingRW /* embeds */
    86  
    87  	log         logging.Logger
    88  	nameToIndex idxvpp.NameToIndex /* contains */
    89  }
    90  
    91  const (
    92  	// ipAddressIndexKey is a secondary index for IP-based look-ups.
    93  	ipAddressIndexKey = "ip_addresses"
    94  )
    95  
    96  // NewIfaceIndex creates a new instance implementing IfaceMetadataIndexRW.
    97  func NewIfaceIndex(logger logging.Logger, title string) IfaceMetadataIndexRW {
    98  	mapping := idxvpp.NewNameToIndex(logger, title, indexMetadata)
    99  	return &ifaceMetadataIndex{
   100  		NamedMappingRW: mapping,
   101  		log:            logger,
   102  		nameToIndex:    mapping,
   103  	}
   104  }
   105  
   106  // LookupByName retrieves a previously stored metadata of interface
   107  // identified by <name>. If there is no interface associated with the give
   108  // name in the mapping, the <exists> is returned as *false* and <metadata>
   109  // as *nil*.
   110  func (ifmx *ifaceMetadataIndex) LookupByName(name string) (metadata *IfaceMetadata, exists bool) {
   111  	meta, found := ifmx.GetValue(name)
   112  	if found {
   113  		if typedMeta, ok := meta.(*IfaceMetadata); ok {
   114  			return typedMeta, found
   115  		}
   116  	}
   117  	return nil, false
   118  }
   119  
   120  // LookupBySwIfIndex retrieves a previously stored interface identified in
   121  // VPP by the given/ <swIfIndex>.
   122  // If there is no interface associated with the given index, <exists> is returned
   123  // as *false* with <name> and <metadata> both set to empty values.
   124  func (ifmx *ifaceMetadataIndex) LookupBySwIfIndex(swIfIndex uint32) (name string, metadata *IfaceMetadata, exists bool) {
   125  	var item idxvpp.WithIndex
   126  	name, item, exists = ifmx.nameToIndex.LookupByIndex(swIfIndex)
   127  	if exists {
   128  		var isIfaceMeta bool
   129  		metadata, isIfaceMeta = item.(*IfaceMetadata)
   130  		if !isIfaceMeta {
   131  			exists = false
   132  		}
   133  	}
   134  	return
   135  }
   136  
   137  // LookupByIP returns a list of interfaces that have the given IP address
   138  // assigned.
   139  func (ifmx *ifaceMetadataIndex) LookupByIP(ip string) []string {
   140  	return ifmx.ListNames(ipAddressIndexKey, ip)
   141  }
   142  
   143  // ListAllInterfaces returns slice of names of all interfaces in the mapping.
   144  func (ifmx *ifaceMetadataIndex) ListAllInterfaces() (names []string) {
   145  	return ifmx.ListAllNames()
   146  }
   147  
   148  // WatchInterfaces allows to subscribe to watch for changes in the mapping
   149  // if interface metadata.
   150  func (ifmx *ifaceMetadataIndex) WatchInterfaces(subscriber string, channel chan<- IfaceMetadataDto) {
   151  	watcher := func(dto idxmap.NamedMappingGenericEvent) {
   152  		typedMeta, ok := dto.Value.(*IfaceMetadata)
   153  		if !ok {
   154  			return
   155  		}
   156  		msg := IfaceMetadataDto{
   157  			NamedMappingEvent: dto.NamedMappingEvent,
   158  			Metadata:          typedMeta,
   159  		}
   160  		timeout := idxmap.DefaultNotifTimeout
   161  		select {
   162  		case channel <- msg:
   163  			// OK
   164  		case <-time.After(timeout):
   165  			ifmx.log.Warnf("Unable to deliver interface watch notification after %v, channel is full", timeout)
   166  		}
   167  	}
   168  	if err := ifmx.Watch(subscriber, watcher); err != nil {
   169  		ifmx.log.Error(err)
   170  	}
   171  }
   172  
   173  // indexMetadata is an index function used for interface metadata.
   174  func indexMetadata(metaData interface{}) map[string][]string {
   175  	indexes := make(map[string][]string)
   176  
   177  	ifMeta, ok := metaData.(*IfaceMetadata)
   178  	if !ok || ifMeta == nil {
   179  		return indexes
   180  	}
   181  
   182  	ip := ifMeta.IPAddresses
   183  	if ip != nil {
   184  		indexes[ipAddressIndexKey] = ip
   185  	}
   186  	return indexes
   187  }