go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/ifplugin/descriptor/span.go (about) 1 // Copyright (c) 2019 PANTHEON.tech 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 "github.com/go-errors/errors" 19 "go.ligato.io/cn-infra/v2/logging" 20 21 kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api" 22 "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/descriptor/adapter" 23 "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/ifaceidx" 24 "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/vppcalls" 25 interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces" 26 ) 27 28 const ( 29 // SpanDescriptorName is the name of the descriptor. 30 SpanDescriptorName = "vpp-span" 31 ) 32 33 // A list of non-retriable errors: 34 var ( 35 ErrSpanWithoutInterface = errors.New("VPP SPAN defined without From/To interface") 36 ErrSpanWithoutDirection = errors.New("VPP SPAN defined without direction (Rx, Tx or Both)") 37 ) 38 39 // SpanDescriptor teaches KVScheduler how to configure VPP SPAN. 40 type SpanDescriptor struct { 41 log logging.Logger 42 spanHandler vppcalls.InterfaceVppAPI 43 intfIndex ifaceidx.IfaceMetadataIndex 44 } 45 46 // NewSpanDescriptor creates a new instance of the SpanDescriptor. 47 func NewSpanDescriptor(spanHandler vppcalls.InterfaceVppAPI, log logging.PluginLogger) (*kvs.KVDescriptor, *SpanDescriptor) { 48 49 ctx := &SpanDescriptor{ 50 spanHandler: spanHandler, 51 log: log.NewLogger("span-descriptor"), 52 } 53 54 typedDescr := &adapter.SpanDescriptor{ 55 Name: SpanDescriptorName, 56 KeySelector: interfaces.ModelSpan.IsKeyValid, 57 KeyLabel: interfaces.ModelSpan.StripKeyPrefix, 58 NBKeyPrefix: interfaces.ModelSpan.KeyPrefix(), 59 ValueTypeName: interfaces.ModelSpan.ProtoName(), 60 Create: ctx.Create, 61 Delete: ctx.Delete, 62 Retrieve: ctx.Retrieve, 63 Validate: ctx.Validate, 64 Dependencies: ctx.Dependencies, 65 RetrieveDependencies: []string{InterfaceDescriptorName}, 66 } 67 68 return adapter.NewSpanDescriptor(typedDescr), ctx 69 } 70 71 // SetInterfaceIndex should be used to provide interface index immediately after 72 // the descriptor registration. 73 func (d *SpanDescriptor) SetInterfaceIndex(intfIndex ifaceidx.IfaceMetadataIndex) { 74 d.intfIndex = intfIndex 75 } 76 77 // Validate checks if required filed are not empty. 78 func (d *SpanDescriptor) Validate(key string, value *interfaces.Span) error { 79 if value.InterfaceFrom == "" && value.InterfaceTo == "" { 80 return kvs.NewInvalidValueError(ErrSpanWithoutInterface, 81 "interface_from", "interface_to") 82 } 83 if value.InterfaceFrom == "" { 84 return kvs.NewInvalidValueError(ErrSpanWithoutInterface, "interface_from") 85 } 86 if value.InterfaceTo == "" { 87 return kvs.NewInvalidValueError(ErrSpanWithoutInterface, "interface_to") 88 } 89 if value.Direction == interfaces.Span_UNKNOWN { 90 return kvs.NewInvalidValueError(ErrSpanWithoutDirection, "direction") 91 } 92 return nil 93 } 94 95 // Create configures SPAN. 96 func (d *SpanDescriptor) Create(key string, value *interfaces.Span) (metadata interface{}, err error) { 97 ifaceFrom, found := d.intfIndex.LookupByName(value.InterfaceFrom) 98 if !found { 99 err = errors.Errorf("failed to find InterfaceFrom %s", value.InterfaceFrom) 100 d.log.Error(err) 101 return nil, err 102 } 103 104 ifaceTo, found := d.intfIndex.LookupByName(value.InterfaceTo) 105 if !found { 106 err = errors.Errorf("failed to find InterfaceTo %s", value.InterfaceTo) 107 d.log.Error(err) 108 return nil, err 109 } 110 111 err = d.spanHandler.AddSpan(ifaceFrom.SwIfIndex, ifaceTo.SwIfIndex, uint8(value.Direction), value.IsL2) 112 if err != nil { 113 err = errors.Errorf("failed to add interface span: %v", err) 114 d.log.Error(err) 115 return nil, err 116 } 117 118 return nil, err 119 } 120 121 // Delete removes SPAN. 122 func (d *SpanDescriptor) Delete(key string, value *interfaces.Span, metadata interface{}) error { 123 var err error 124 ifaceFrom, found := d.intfIndex.LookupByName(value.InterfaceFrom) 125 if !found { 126 err = errors.Errorf("failed to find InterfaceFrom %s", value.InterfaceFrom) 127 d.log.Error(err) 128 return err 129 } 130 131 ifaceTo, found := d.intfIndex.LookupByName(value.InterfaceTo) 132 if !found { 133 err = errors.Errorf("failed to find InterfaceTo %s", value.InterfaceTo) 134 d.log.Error(err) 135 return err 136 } 137 138 err = d.spanHandler.DelSpan(ifaceFrom.SwIfIndex, ifaceTo.SwIfIndex, value.IsL2) 139 if err != nil { 140 err = errors.Errorf("failed to delete interface span: %v", err) 141 d.log.Error(err) 142 return err 143 } 144 145 return err 146 } 147 148 // Retrieve returns all records from VPP SPAN table. 149 func (d *SpanDescriptor) Retrieve(correlate []adapter.SpanKVWithMetadata) (retrieved []adapter.SpanKVWithMetadata, err error) { 150 spans, err := d.spanHandler.DumpSpan() 151 if err != nil { 152 d.log.Error(err) 153 return retrieved, err 154 } 155 156 var nameFrom, nameTo string 157 var exists bool 158 for _, s := range spans { 159 nameFrom, _, exists = d.intfIndex.LookupBySwIfIndex(s.SwIfIndexFrom) 160 if !exists { 161 d.log.Debugf("failed to find interface with index %d", s.SwIfIndexFrom) 162 continue 163 } 164 nameTo, _, exists = d.intfIndex.LookupBySwIfIndex(s.SwIfIndexTo) 165 if !exists { 166 d.log.Debugf("failed to find interface with index %d", s.SwIfIndexTo) 167 continue 168 } 169 retrieved = append(retrieved, adapter.SpanKVWithMetadata{ 170 Key: interfaces.SpanKey(nameFrom, nameTo), 171 Value: &interfaces.Span{ 172 InterfaceFrom: nameFrom, 173 InterfaceTo: nameTo, 174 Direction: interfaces.Span_Direction(s.Direction), 175 IsL2: s.IsL2, 176 }, 177 Origin: kvs.FromNB, 178 }) 179 } 180 return retrieved, nil 181 } 182 183 // Dependencies lists both From and To interfaces as dependencies. 184 func (d *SpanDescriptor) Dependencies(key string, value *interfaces.Span) []kvs.Dependency { 185 return []kvs.Dependency{ 186 { 187 Label: "interface-from", 188 Key: interfaces.InterfaceKey(value.InterfaceFrom), 189 }, 190 { 191 Label: "interface-to", 192 Key: interfaces.InterfaceKey(value.InterfaceTo), 193 }, 194 } 195 }