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 }