go.ligato.io/vpp-agent/v3@v3.5.0/pkg/idxvpp/idxvpp.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 idxvpp 16 17 import ( 18 "strconv" 19 "time" 20 21 "go.ligato.io/cn-infra/v2/idxmap" 22 "go.ligato.io/cn-infra/v2/idxmap/mem" 23 "go.ligato.io/cn-infra/v2/logging" 24 ) 25 26 var DefaultNotifTimeout = time.Millisecond * 100 27 28 // WithIndex is interface that items with integer handle must implement to get 29 // indexed by NameToIndex. 30 type WithIndex interface { 31 // GetIndex should return integer handle assigned to the item. 32 GetIndex() uint32 33 } 34 35 // NameToIndex is the "user API" to the registry of items with integer handles. 36 // It provides read-only access intended for plugins that need to do the conversions 37 // between logical names from NB and VPP/Linux item IDs. 38 type NameToIndex interface { 39 // LookupByName retrieves a previously stored item identified by 40 // <name>. If there is no item associated with the give name in the mapping, 41 // the <exists> is returned as *false* and <item> as *nil*. 42 LookupByName(name string) (item WithIndex, exists bool) 43 44 // LookupByIndex retrieves a previously stored item identified in VPP/Linux 45 // by the given <index>. 46 // If there is no item associated with the given index, <exists> is returned 47 // as *false* with <name> and <item> both set to empty values. 48 LookupByIndex(index uint32) (name string, item WithIndex, exists bool) 49 50 // WatchItems subscribes to receive notifications about the changes in the 51 // mapping related to items with integer handles. 52 WatchItems(subscriber string, channel chan<- NameToIndexDto) 53 } 54 55 // NameToIndexRW is the "owner API" to the NameToIndex registry. Using this 56 // API the owner is able to add/update and delete associations between logical 57 // names and VPP/Linux items identified by integer handles. 58 type NameToIndexRW interface { 59 NameToIndex 60 idxmap.NamedMappingRW 61 } 62 63 // OnlyIndex can be used to add items into NameToIndex with the integer handle 64 // as the only information associated with each item. 65 type OnlyIndex struct { 66 Index uint32 67 } 68 69 // GetIndex returns index assigned to the item. 70 func (item *OnlyIndex) GetIndex() uint32 { 71 return item.Index 72 } 73 74 // NameToIndexDto represents an item sent through watch channel in NameToIndex. 75 // In contrast to NamedMappingGenericEvent, it contains item casted to WithIndex. 76 type NameToIndexDto struct { 77 idxmap.NamedMappingEvent 78 Item WithIndex 79 } 80 81 // nameToIndex implements NamedMapping for items with integer handles. 82 type nameToIndex struct { 83 idxmap.NamedMappingRW 84 log logging.Logger 85 } 86 87 const ( 88 // indexKey is a secondary index used to create association between 89 // item name and the integer handle. 90 indexKey = "index" 91 ) 92 93 // NewNameToIndex creates a new instance implementing NameToIndexRW. 94 // User can optionally extend the secondary indexes through <indexFunction>. 95 func NewNameToIndex(logger logging.Logger, title string, 96 indexFunction mem.IndexFunction) NameToIndexRW { 97 return &nameToIndex{ 98 NamedMappingRW: mem.NewNamedMapping(logger, title, 99 func(item interface{}) map[string][]string { 100 idxs := internalIndexFunction(item) 101 102 if indexFunction != nil { 103 userIdxs := indexFunction(item) 104 for k, v := range userIdxs { 105 idxs[k] = v 106 } 107 } 108 return idxs 109 }), 110 } 111 } 112 113 // LookupByName retrieves a previously stored item identified by 114 // <name>. If there is no item associated with the give name in the mapping, 115 // the <exists> is returned as *false* and <item> as *nil*. 116 func (idx *nameToIndex) LookupByName(name string) (item WithIndex, exists bool) { 117 value, found := idx.GetValue(name) 118 if found { 119 if itemWithIndex, ok := value.(WithIndex); ok { 120 return itemWithIndex, found 121 } 122 } 123 return nil, false 124 } 125 126 // LookupByIndex retrieves a previously stored item identified in VPP/Linux 127 // by the given <index>. 128 // If there is no item associated with the given index, <exists> is returned 129 // as *false* with <name> and <item> both set to empty values. 130 func (idx *nameToIndex) LookupByIndex(index uint32) (name string, item WithIndex, exists bool) { 131 res := idx.ListNames(indexKey, strconv.FormatUint(uint64(index), 10)) 132 if len(res) != 1 { 133 return 134 } 135 value, found := idx.GetValue(res[0]) 136 if found { 137 if itemWithIndex, ok := value.(WithIndex); ok { 138 return res[0], itemWithIndex, found 139 } 140 } 141 return 142 } 143 144 // WatchItems subscribes to receive notifications about the changes in the 145 // mapping related to items with integer handles. 146 func (idx *nameToIndex) WatchItems(subscriber string, channel chan<- NameToIndexDto) { 147 watcher := func(dto idxmap.NamedMappingGenericEvent) { 148 itemWithIndex, ok := dto.Value.(WithIndex) 149 if !ok { 150 return 151 } 152 msg := NameToIndexDto{ 153 NamedMappingEvent: dto.NamedMappingEvent, 154 Item: itemWithIndex, 155 } 156 select { 157 case channel <- msg: 158 case <-time.After(DefaultNotifTimeout): 159 idx.log.Warn("Unable to deliver notification") 160 } 161 } 162 if err := idx.Watch(subscriber, watcher); err != nil { 163 idx.log.Error(err) 164 } 165 } 166 167 // internalIndexFunction is an index function used internally for nameToIndex. 168 func internalIndexFunction(item interface{}) map[string][]string { 169 indexes := map[string][]string{} 170 itemWithIndex, ok := item.(WithIndex) 171 if !ok || itemWithIndex == nil { 172 return indexes 173 } 174 175 indexes[indexKey] = []string{strconv.FormatUint(uint64(itemWithIndex.GetIndex()), 10)} 176 return indexes 177 }