go.ligato.io/vpp-agent/v3@v3.5.0/plugins/linux/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/idxmap/mem" 22 "go.ligato.io/cn-infra/v2/logging" 23 "google.golang.org/protobuf/proto" 24 25 linux_namespace "go.ligato.io/vpp-agent/v3/proto/ligato/linux/namespace" 26 ) 27 28 // LinuxIfMetadataIndex provides read-only access to mapping with Linux interface 29 // metadata. It extends from NameToIndex. 30 type LinuxIfMetadataIndex interface { 31 // LookupByName retrieves a previously stored metadata of interface 32 // identified by logical <name>. If there is no interface associated with 33 // the given name in the mapping, the <exists> is returned as *false* and 34 // <metadata> as *nil*. 35 LookupByName(name string) (metadata *LinuxIfMetadata, exists bool) 36 37 // LookupByVPPTap retrieves a previously configured TAP_TO_VPP interface 38 // by the logical name of the associated VPP-side of the TAP. 39 // If there is no such interface, <exists> is returned as *false* with <name> 40 // and <metadata> both set to empty values. 41 LookupByVPPTap(vppTapName string) (name string, metadata *LinuxIfMetadata, exists bool) 42 43 // LookupByHostName retrieves a previously configured Linux interface 44 // by the host interface name inside the given namespace. 45 // If there is no such interface, <exists> is returned as *false* with <name> 46 // and <metadata> both set to empty values. 47 LookupByHostName(hostname string, ns *linux_namespace.NetNamespace) (name string, 48 metadata *LinuxIfMetadata, exists bool) 49 50 // ListAllInterfaces returns slice of names of all interfaces in the mapping. 51 ListAllInterfaces() (names []string) 52 53 // WatchInterfaces allows to subscribe to watch for changes in the mapping 54 // of interface metadata. 55 WatchInterfaces(subscriber string, channel chan<- LinuxIfMetadataIndexDto) error 56 } 57 58 // LinuxIfMetadataIndexRW provides read-write access to mapping with interface 59 // metadata. 60 type LinuxIfMetadataIndexRW interface { 61 LinuxIfMetadataIndex 62 idxmap.NamedMappingRW 63 } 64 65 // LinuxIfMetadata collects metadata for Linux interface used in secondary lookups. 66 type LinuxIfMetadata struct { 67 LinuxIfIndex int 68 VPPTapName string // empty for VETHs 69 Namespace *linux_namespace.NetNamespace 70 HostIfName string 71 VrfMasterIf string 72 VrfDevRT uint32 // only set for VRF_DEVICE 73 } 74 75 // LinuxIfMetadataIndexDto represents an item sent through watch channel in LinuxIfMetadataIndex. 76 // In contrast to NamedMappingGenericEvent, it contains typed interface metadata. 77 type LinuxIfMetadataIndexDto struct { 78 idxmap.NamedMappingEvent 79 Metadata *LinuxIfMetadata 80 } 81 82 // linuxIfMetadataIndex is type-safe implementation of mapping between interface 83 // name and metadata of type *LinuxIfMetadata. 84 type linuxIfMetadataIndex struct { 85 idxmap.NamedMappingRW /* embeds */ 86 log logging.Logger 87 } 88 89 const ( 90 // tapVPPNameIndexKey is used as a secondary key used to search TAP_TO_VPP 91 // interface by the logical name of the VPP-side of the TAP. 92 tapVPPNameIndexKey = "tap-vpp-name" 93 94 // hostNameIndexKey is used as a secondary key used to search Linux 95 // interfaces by the host interface name. 96 hostNameIndexKey = "host-iface-name" 97 ) 98 99 // NewLinuxIfIndex creates a new instance implementing LinuxIfMetadataIndexRW. 100 func NewLinuxIfIndex(logger logging.Logger, title string) LinuxIfMetadataIndexRW { 101 return &linuxIfMetadataIndex{ 102 NamedMappingRW: mem.NewNamedMapping(logger, title, indexMetadata), 103 } 104 } 105 106 // LookupByName retrieves a previously stored metadata of interface 107 // identified by logical <name>. If there is no interface associated with 108 // the give/ name in the mapping, the <exists> is returned as *false* and 109 // <metadata> as *nil*. 110 func (ifmx *linuxIfMetadataIndex) LookupByName(name string) (metadata *LinuxIfMetadata, exists bool) { 111 meta, found := ifmx.GetValue(name) 112 if found { 113 if typedMeta, ok := meta.(*LinuxIfMetadata); ok { 114 return typedMeta, found 115 } 116 } 117 return nil, false 118 } 119 120 // LookupByVPPTap retrieves a previously configured TAP_TO_VPP interface 121 // by the logical name of the associated VPP-side of the TAP. 122 // If there is no such interface, <exists> is returned as *false* with <name> 123 // and <metadata> both set to empty values. 124 func (ifmx *linuxIfMetadataIndex) LookupByVPPTap(vppTapName string) (name string, metadata *LinuxIfMetadata, exists bool) { 125 res := ifmx.ListNames(tapVPPNameIndexKey, vppTapName) 126 if len(res) != 1 { 127 return 128 } 129 untypedMeta, found := ifmx.GetValue(res[0]) 130 if found { 131 if ifMeta, ok := untypedMeta.(*LinuxIfMetadata); ok { 132 return res[0], ifMeta, found 133 } 134 } 135 return 136 } 137 138 // LookupByHostName retrieves a previously configured Linux interface 139 // by the host interface name inside the given namespace. 140 // If there is no such interface, <exists> is returned as *false* with <name> 141 // and <metadata> both set to empty values. 142 func (ifmx *linuxIfMetadataIndex) LookupByHostName(hostname string, ns *linux_namespace.NetNamespace) ( 143 name string, metadata *LinuxIfMetadata, exists bool) { 144 145 res := ifmx.ListNames(hostNameIndexKey, hostname) 146 for _, iface := range res { 147 untypedMeta, found := ifmx.GetValue(iface) 148 if found { 149 if ifMeta, ok := untypedMeta.(*LinuxIfMetadata); ok { 150 if proto.Equal(ns, ifMeta.Namespace) { 151 return iface, ifMeta, true 152 } 153 } 154 } 155 } 156 return 157 } 158 159 // ListAllInterfaces returns slice of names of all interfaces in the mapping. 160 func (ifmx *linuxIfMetadataIndex) ListAllInterfaces() (names []string) { 161 return ifmx.ListAllNames() 162 } 163 164 // WatchInterfaces allows to subscribe to watch for changes in the mapping 165 // if interface metadata. 166 func (ifmx *linuxIfMetadataIndex) WatchInterfaces(subscriber string, channel chan<- LinuxIfMetadataIndexDto) error { 167 watcher := func(dto idxmap.NamedMappingGenericEvent) { 168 typedMeta, ok := dto.Value.(*LinuxIfMetadata) 169 if !ok { 170 return 171 } 172 msg := LinuxIfMetadataIndexDto{ 173 NamedMappingEvent: dto.NamedMappingEvent, 174 Metadata: typedMeta, 175 } 176 select { 177 case channel <- msg: 178 case <-time.After(idxmap.DefaultNotifTimeout): 179 ifmx.log.Warn("Unable to deliver notification") 180 } 181 } 182 return ifmx.Watch(subscriber, watcher) 183 } 184 185 // indexMetadata is an index function used for interface metadata. 186 func indexMetadata(metaData interface{}) map[string][]string { 187 indexes := make(map[string][]string) 188 189 ifMeta, ok := metaData.(*LinuxIfMetadata) 190 if !ok || ifMeta == nil { 191 return indexes 192 } 193 194 if ifMeta.VPPTapName != "" { 195 indexes[tapVPPNameIndexKey] = []string{ifMeta.VPPTapName} 196 } 197 indexes[hostNameIndexKey] = []string{ifMeta.HostIfName} 198 199 return indexes 200 }