go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/l2plugin/descriptor/fib.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 descriptor 16 17 import ( 18 "strings" 19 20 "github.com/pkg/errors" 21 "go.ligato.io/cn-infra/v2/logging" 22 23 kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api" 24 vpp_ifdescriptor "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/descriptor" 25 "go.ligato.io/vpp-agent/v3/plugins/vpp/l2plugin/descriptor/adapter" 26 "go.ligato.io/vpp-agent/v3/plugins/vpp/l2plugin/vppcalls" 27 l2 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l2" 28 ) 29 30 const ( 31 // FIBDescriptorName is the name of the descriptor for VPP L2 FIBs. 32 FIBDescriptorName = "vpp-l2-fib" 33 34 // dependency labels 35 bridgedInterfaceDep = "bridged-interface" 36 bridgeDomainDep = "bridge-domain" 37 ) 38 39 // A list of non-retriable errors: 40 var ( 41 // ErrFIBWithoutHwAddr is returned when VPP L2 FIB has undefined hardware 42 // address. 43 ErrFIBWithoutHwAddr = errors.New("VPP L2 FIB defined without hardware address") 44 45 // ErrFIBWithoutBD is returned when VPP L2 FIB has undefined bridge domain. 46 ErrFIBWithoutBD = errors.New("VPP L2 FIB defined without bridge domain") 47 48 // ErrForwardFIBWithoutInterface is returned when VPP L2 FORWARD FIB has undefined outgoing interface. 49 ErrForwardFIBWithoutInterface = errors.New("VPP L2 FORWARD FIB defined without outgoing interface") 50 ) 51 52 // FIBDescriptor teaches KVScheduler how to configure VPP L2 FIBs. 53 type FIBDescriptor struct { 54 // dependencies 55 log logging.Logger 56 fibHandler vppcalls.FIBVppAPI 57 } 58 59 // NewFIBDescriptor creates a new instance of the FIB descriptor. 60 func NewFIBDescriptor(fibHandler vppcalls.FIBVppAPI, log logging.PluginLogger) *FIBDescriptor { 61 62 return &FIBDescriptor{ 63 fibHandler: fibHandler, 64 log: log.NewLogger("l2-fib-descriptor"), 65 } 66 } 67 68 // GetDescriptor returns descriptor suitable for registration (via adapter) with 69 // the KVScheduler. 70 func (d *FIBDescriptor) GetDescriptor() *adapter.FIBDescriptor { 71 return &adapter.FIBDescriptor{ 72 Name: FIBDescriptorName, 73 NBKeyPrefix: l2.ModelFIBEntry.KeyPrefix(), 74 ValueTypeName: l2.ModelFIBEntry.ProtoName(), 75 KeySelector: l2.ModelFIBEntry.IsKeyValid, 76 KeyLabel: l2.ModelFIBEntry.StripKeyPrefix, 77 ValueComparator: d.EquivalentFIBs, 78 Validate: d.Validate, 79 Create: d.Create, 80 Delete: d.Delete, 81 Retrieve: d.Retrieve, 82 Dependencies: d.Dependencies, 83 RetrieveDependencies: []string{vpp_ifdescriptor.InterfaceDescriptorName, BridgeDomainDescriptorName}, 84 } 85 } 86 87 // EquivalentFIBs is case-insensitive comparison function for l2.FIBEntry. 88 func (d *FIBDescriptor) EquivalentFIBs(key string, oldFIB, newFIB *l2.FIBEntry) bool { 89 // parameters compared as usually 90 if oldFIB.Action != newFIB.Action || oldFIB.BridgeDomain != newFIB.BridgeDomain { 91 return false 92 } 93 94 // parameters relevant only for FORWARD FIBs 95 if oldFIB.Action == l2.FIBEntry_FORWARD { 96 if oldFIB.OutgoingInterface != newFIB.OutgoingInterface || 97 oldFIB.BridgedVirtualInterface != newFIB.BridgedVirtualInterface || 98 oldFIB.StaticConfig != newFIB.StaticConfig { 99 return false 100 } 101 } 102 103 // MAC addresses compared case-insensitively 104 return strings.EqualFold(oldFIB.PhysAddress, newFIB.PhysAddress) 105 } 106 107 // Validate validates VPP L2 FIB configuration. 108 func (d *FIBDescriptor) Validate(key string, fib *l2.FIBEntry) error { 109 if fib.PhysAddress == "" { 110 return kvs.NewInvalidValueError(ErrFIBWithoutHwAddr, "phys_address") 111 } 112 if fib.Action == l2.FIBEntry_FORWARD && fib.OutgoingInterface == "" { 113 return kvs.NewInvalidValueError(ErrForwardFIBWithoutInterface, "action", "outgoing_interface") 114 } 115 if fib.BridgeDomain == "" { 116 return kvs.NewInvalidValueError(ErrFIBWithoutBD, "bridge_domain") 117 } 118 return nil 119 } 120 121 // Create adds new L2 FIB. 122 func (d *FIBDescriptor) Create(key string, fib *l2.FIBEntry) (metadata interface{}, err error) { 123 // add L2 FIB 124 err = d.fibHandler.AddL2FIB(fib) 125 if err != nil { 126 d.log.Error(err) 127 } 128 return nil, err 129 } 130 131 // Delete removes VPP L2 FIB. 132 func (d *FIBDescriptor) Delete(key string, fib *l2.FIBEntry, metadata interface{}) error { 133 err := d.fibHandler.DeleteL2FIB(fib) 134 if err != nil { 135 d.log.Error(err) 136 } 137 return err 138 } 139 140 // Retrieve returns all configured VPP L2 FIBs. 141 func (d *FIBDescriptor) Retrieve(correlate []adapter.FIBKVWithMetadata) (retrieved []adapter.FIBKVWithMetadata, err error) { 142 fibs, err := d.fibHandler.DumpL2FIBs() 143 if err != nil { 144 d.log.Error(err) 145 return retrieved, err 146 } 147 for _, fib := range fibs { 148 retrieved = append(retrieved, adapter.FIBKVWithMetadata{ 149 Key: l2.FIBKey(fib.Fib.BridgeDomain, fib.Fib.PhysAddress), 150 Value: fib.Fib, 151 Origin: kvs.UnknownOrigin, // there can be automatically created FIBs 152 }) 153 } 154 155 return retrieved, nil 156 } 157 158 // Dependencies for FIBs are: 159 // - FORWARD FIB: bridge domain + outgoing interface already put into the bridge domain 160 // - DROP FIB: bridge domain 161 func (d *FIBDescriptor) Dependencies(key string, fib *l2.FIBEntry) (dependencies []kvs.Dependency) { 162 if fib.Action == l2.FIBEntry_FORWARD { 163 dependencies = append(dependencies, kvs.Dependency{ 164 Label: bridgedInterfaceDep, 165 Key: l2.BDInterfaceKey(fib.BridgeDomain, fib.OutgoingInterface), 166 }) 167 } else { 168 dependencies = append(dependencies, kvs.Dependency{ 169 Label: bridgeDomainDep, 170 Key: l2.BridgeDomainKey(fib.BridgeDomain), 171 }) 172 } 173 return dependencies 174 }