go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/abfplugin/descriptor/abf.go (about) 1 // Copyright (c) 2019 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 descriptor 16 17 import ( 18 "github.com/go-errors/errors" 19 "google.golang.org/protobuf/proto" 20 prototypes "google.golang.org/protobuf/types/known/emptypb" 21 22 "go.ligato.io/cn-infra/v2/idxmap" 23 "go.ligato.io/cn-infra/v2/logging" 24 25 "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api" 26 "go.ligato.io/vpp-agent/v3/plugins/vpp/abfplugin/abfidx" 27 "go.ligato.io/vpp-agent/v3/plugins/vpp/abfplugin/descriptor/adapter" 28 "go.ligato.io/vpp-agent/v3/plugins/vpp/abfplugin/vppcalls" 29 "go.ligato.io/vpp-agent/v3/plugins/vpp/aclplugin/aclidx" 30 "go.ligato.io/vpp-agent/v3/plugins/vpp/aclplugin/descriptor" 31 ifdescriptor "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/descriptor" 32 abf "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/abf" 33 acl "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/acl" 34 vpp_interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces" 35 ) 36 37 const ( 38 // ABFDescriptorName is descriptor name 39 ABFDescriptorName = "vpp-abf" 40 41 // dependency labels 42 aclDep = "acl-exists" 43 ) 44 45 // A list of non-retriable errors: 46 var ( 47 // ErrABFWithoutACL is returned when ABF configuration does not contain associated access list. 48 ErrABFWithoutACL = errors.New("ABF configuration defined without ACL") 49 ) 50 51 // ABFDescriptor is descriptor for ABF 52 type ABFDescriptor struct { 53 // dependencies 54 log logging.Logger 55 abfHandler vppcalls.ABFVppAPI 56 57 // runtime 58 aclIndex aclidx.ACLMetadataIndex 59 } 60 61 // NewABFDescriptor is constructor for ABF descriptor and returns descriptor 62 // suitable for registration (via adapter) with the KVScheduler. 63 func NewABFDescriptor( 64 abfHandler vppcalls.ABFVppAPI, 65 aclIndex aclidx.ACLMetadataIndex, 66 logger logging.PluginLogger, 67 ) *api.KVDescriptor { 68 ctx := &ABFDescriptor{ 69 log: logger.NewLogger("abf-descriptor"), 70 aclIndex: aclIndex, 71 abfHandler: abfHandler, 72 } 73 typedDescr := &adapter.ABFDescriptor{ 74 Name: ABFDescriptorName, 75 NBKeyPrefix: abf.ModelABF.KeyPrefix(), 76 ValueTypeName: abf.ModelABF.ProtoName(), 77 KeySelector: abf.ModelABF.IsKeyValid, 78 KeyLabel: abf.ModelABF.StripKeyPrefix, 79 WithMetadata: true, 80 MetadataMapFactory: func() idxmap.NamedMappingRW { 81 return abfidx.NewABFIndex(ctx.log, "vpp-abf-index") 82 }, 83 ValueComparator: ctx.EquivalentABFs, 84 Validate: ctx.Validate, 85 Create: ctx.Create, 86 Delete: ctx.Delete, 87 Retrieve: ctx.Retrieve, 88 DerivedValues: ctx.DerivedValues, 89 Dependencies: ctx.Dependencies, 90 RetrieveDependencies: []string{ifdescriptor.InterfaceDescriptorName, descriptor.ACLDescriptorName}, 91 } 92 return adapter.NewABFDescriptor(typedDescr) 93 } 94 95 // EquivalentABFs compares related ACL name, list of attached interfaces and forwarding paths to 96 // specify ABS equality. 97 func (d *ABFDescriptor) EquivalentABFs(key string, oldABF, newABF *abf.ABF) bool { 98 // check index and associated ACL 99 if oldABF.AclName != newABF.AclName { 100 return false 101 } 102 103 // compare attached interfaces 104 if len(oldABF.AttachedInterfaces) != len(newABF.AttachedInterfaces) { 105 return false 106 } 107 if !equivalentABFAttachedInterfaces(oldABF.AttachedInterfaces, newABF.AttachedInterfaces) { 108 return false 109 } 110 111 // compare forwarding paths 112 if len(oldABF.ForwardingPaths) != len(newABF.ForwardingPaths) { 113 return false 114 } 115 return equivalentABFForwardingPaths(oldABF.ForwardingPaths, newABF.ForwardingPaths) 116 } 117 118 // Validate validates VPP ABF configuration. 119 func (d *ABFDescriptor) Validate(key string, abfData *abf.ABF) error { 120 if abfData.AclName == "" { 121 return api.NewInvalidValueError(ErrABFWithoutACL, "acl_name") 122 } 123 return nil 124 } 125 126 // Create validates ABF (mainly index), verifies ACL existence and configures ABF policy. Attached interfaces 127 // are put to metadata together with the ABF index to make it available for other ABF descriptors. 128 func (d *ABFDescriptor) Create(key string, abfData *abf.ABF) (*abfidx.ABFMetadata, error) { 129 // get ACL index 130 aclData, exists := d.aclIndex.LookupByName(abfData.AclName) 131 if !exists { 132 err := errors.Errorf("failed to obtain metadata for ACL %s", abfData.AclName) 133 d.log.Error(err) 134 return nil, err 135 } 136 137 // add new ABF policy 138 if err := d.abfHandler.AddAbfPolicy(abfData.Index, aclData.Index, abfData.ForwardingPaths); err != nil { 139 d.log.Error(err) 140 return nil, err 141 } 142 143 // fill the metadata 144 metadata := &abfidx.ABFMetadata{ 145 Index: abfData.Index, 146 Attached: abfData.AttachedInterfaces, 147 } 148 149 return metadata, nil 150 } 151 152 // Delete removes ABF policy 153 func (d *ABFDescriptor) Delete(key string, abfData *abf.ABF, metadata *abfidx.ABFMetadata) error { 154 // ACL ID is not required 155 return d.abfHandler.DeleteAbfPolicy(metadata.Index, abfData.ForwardingPaths) 156 } 157 158 // Retrieve returns ABF policies from the VPP. 159 func (d *ABFDescriptor) Retrieve(correlate []adapter.ABFKVWithMetadata) (abfs []adapter.ABFKVWithMetadata, err error) { 160 // Retrieve VPP configuration. 161 abfPolicies, err := d.abfHandler.DumpABFPolicy() 162 if err != nil { 163 return nil, errors.Errorf("failed to dump ABF policy: %v", err) 164 } 165 166 for _, abfPolicy := range abfPolicies { 167 abfs = append(abfs, adapter.ABFKVWithMetadata{ 168 Key: abf.Key(abfPolicy.ABF.Index), 169 Value: abfPolicy.ABF, 170 Metadata: &abfidx.ABFMetadata{ 171 Index: abfPolicy.Meta.PolicyID, 172 Attached: abfPolicy.ABF.AttachedInterfaces, 173 }, 174 Origin: api.FromNB, 175 }) 176 } 177 178 return abfs, nil 179 } 180 181 // DerivedValues returns list of derived values for ABF. 182 func (d *ABFDescriptor) DerivedValues(key string, value *abf.ABF) (derived []api.KeyValuePair) { 183 for _, attachedIf := range value.GetAttachedInterfaces() { 184 derived = append(derived, api.KeyValuePair{ 185 Key: abf.ToInterfaceKey(value.Index, attachedIf.InputInterface), 186 Value: &prototypes.Empty{}, 187 }) 188 } 189 return derived 190 } 191 192 // A list of ABF dependencies (ACL + forwarding path interfaces). 193 func (d *ABFDescriptor) Dependencies(key string, abfData *abf.ABF) (dependencies []api.Dependency) { 194 // forwarding path interfaces 195 for _, abfDataLabel := range abfData.ForwardingPaths { 196 if abfDataLabel.InterfaceName != "" { 197 dependencies = append(dependencies, api.Dependency{ 198 Label: interfaceDep, 199 Key: vpp_interfaces.InterfaceKey(abfDataLabel.InterfaceName), 200 }) 201 } 202 } 203 // access list 204 dependencies = append(dependencies, api.Dependency{ 205 Label: aclDep, 206 Key: acl.Key(abfData.AclName), 207 }) 208 209 return dependencies 210 } 211 212 func equivalentABFAttachedInterfaces(oldIfs, newIfs []*abf.ABF_AttachedInterface) bool { 213 for _, oldIf := range oldIfs { 214 var found bool 215 for _, newIf := range newIfs { 216 if proto.Equal(oldIf, newIf) { 217 found = true 218 } 219 } 220 if !found { 221 return false 222 } 223 } 224 return true 225 } 226 227 func equivalentABFForwardingPaths(oldPaths, newPaths []*abf.ABF_ForwardingPath) bool { 228 for _, oldPath := range oldPaths { 229 var found bool 230 for _, newPath := range newPaths { 231 if oldPath.InterfaceName == newPath.InterfaceName && 232 oldPath.NextHopIp == newPath.NextHopIp && 233 oldPath.Weight == newPath.Weight && 234 oldPath.Preference == newPath.Preference && 235 oldPath.Dvr == newPath.Dvr { 236 found = true 237 } 238 } 239 if !found { 240 return false 241 } 242 } 243 return true 244 }