go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/l3plugin/descriptor/vrf_table.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 "fmt" 19 "math" 20 "strings" 21 22 "github.com/pkg/errors" 23 "go.ligato.io/cn-infra/v2/idxmap" 24 "go.ligato.io/cn-infra/v2/logging" 25 "google.golang.org/protobuf/proto" 26 27 kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api" 28 "go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/descriptor/adapter" 29 "go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/vppcalls" 30 "go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/vrfidx" 31 l3 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l3" 32 ) 33 34 const ( 35 // VrfTableDescriptorName is the name of the descriptor for VRF tables. 36 VrfTableDescriptorName = "vpp-vrf-table" 37 38 // how many characters a VRF table label is allowed to have 39 // - determined by much fits into the binary API (64 null-terminated character string) 40 labelLengthLimit = 63 41 ) 42 43 // A list of non-retriable errors: 44 var ( 45 // ErrVrfTableLabelTooLong is returned when VRF table label exceeds the length limit. 46 ErrVrfTableLabelTooLong = errors.New("VPP VRF table label exceeds the length limit (63 characters)") 47 ) 48 49 // VrfTableDescriptor teaches KVScheduler how to configure VPP VRF tables. 50 type VrfTableDescriptor struct { 51 log logging.Logger 52 vtHandler vppcalls.VrfTableVppAPI 53 } 54 55 // NewVrfTableDescriptor creates a new instance of the VrfTable descriptor. 56 func NewVrfTableDescriptor( 57 vtHandler vppcalls.VrfTableVppAPI, log logging.PluginLogger) *kvs.KVDescriptor { 58 59 ctx := &VrfTableDescriptor{ 60 vtHandler: vtHandler, 61 log: log.NewLogger("vrf-table-descriptor"), 62 } 63 typedDescr := &adapter.VrfTableDescriptor{ 64 Name: VrfTableDescriptorName, 65 NBKeyPrefix: l3.ModelVrfTable.KeyPrefix(), 66 ValueTypeName: l3.ModelVrfTable.ProtoName(), 67 KeySelector: l3.ModelVrfTable.IsKeyValid, 68 KeyLabel: l3.ModelVrfTable.StripKeyPrefix, 69 WithMetadata: true, 70 MetadataMapFactory: ctx.MetadataFactory, 71 ValueComparator: ctx.EquivalentVrfTables, 72 Validate: ctx.Validate, 73 Create: ctx.Create, 74 Update: ctx.Update, 75 UpdateWithRecreate: ctx.UpdateWithRecreate, 76 Delete: ctx.Delete, 77 Retrieve: ctx.Retrieve, 78 } 79 return adapter.NewVrfTableDescriptor(typedDescr) 80 } 81 82 // EquivalentVrfTables is a comparison function for l3.VrfTable. 83 func (d *VrfTableDescriptor) EquivalentVrfTables(key string, oldVrfTable, newVrfTable *l3.VrfTable) bool { 84 if getVrfTableLabel(oldVrfTable) != getVrfTableLabel(newVrfTable) || 85 !proto.Equal(oldVrfTable.FlowHashSettings, newVrfTable.FlowHashSettings) { 86 return false 87 } 88 return true 89 } 90 91 // MetadataFactory is a factory for index-map customized for VRFs. 92 func (d *VrfTableDescriptor) MetadataFactory() idxmap.NamedMappingRW { 93 return vrfidx.NewVRFIndex(d.log, "vpp-vrf-index") 94 } 95 96 // Validate validates configuration of VPP VRF table. 97 func (d *VrfTableDescriptor) Validate(key string, vrfTable *l3.VrfTable) (err error) { 98 if len(vrfTable.Label) > labelLengthLimit { 99 return kvs.NewInvalidValueError(ErrVrfTableLabelTooLong, "label") 100 } 101 return nil 102 } 103 104 // Create adds VPP VRF table. 105 func (d *VrfTableDescriptor) Create(key string, vrfTable *l3.VrfTable) (metadata *vrfidx.VRFMetadata, err error) { 106 err = d.vtHandler.AddVrfTable(vrfTable) 107 if err != nil { 108 return nil, err 109 } 110 111 if vrfTable.FlowHashSettings != nil { 112 err = d.vtHandler.SetVrfFlowHashSettings(vrfTable.Id, vrfTable.Protocol == l3.VrfTable_IPV6, vrfTable.FlowHashSettings) 113 if err != nil { 114 return nil, err 115 } 116 } 117 118 // fill the metadata 119 metadata = &vrfidx.VRFMetadata{ 120 Index: vrfTable.Id, 121 Protocol: vrfTable.Protocol, 122 } 123 124 return metadata, nil 125 } 126 127 // UpdateWithRecreate returns true if a VRF update needs to be performed via re-crate. 128 func (d *VrfTableDescriptor) UpdateWithRecreate(_ string, oldVrfTable, newVrfTable *l3.VrfTable, _ *vrfidx.VRFMetadata) bool { 129 if oldVrfTable.Protocol == newVrfTable.Protocol && oldVrfTable.Id == newVrfTable.Id { 130 return false 131 } 132 return true // protocol or VRF ID changed = recreate 133 } 134 135 // Update updates VPP VRF table (ony if protocol or VRF ID has not changed). 136 func (d *VrfTableDescriptor) Update(_ string, oldVrfTable, newVrfTable *l3.VrfTable, _ *vrfidx.VRFMetadata) ( 137 metadata *vrfidx.VRFMetadata, err error) { 138 139 if !proto.Equal(oldVrfTable.FlowHashSettings, newVrfTable.FlowHashSettings) { 140 newSettings := newVrfTable.FlowHashSettings 141 if newSettings == nil { 142 newSettings = defaultVrfFlowHashSettings() 143 } 144 err = d.vtHandler.SetVrfFlowHashSettings(newVrfTable.Id, newVrfTable.Protocol == l3.VrfTable_IPV6, newSettings) 145 } 146 147 // fill the metadata 148 metadata = &vrfidx.VRFMetadata{ 149 Index: newVrfTable.Id, 150 Protocol: newVrfTable.Protocol, 151 } 152 return metadata, err 153 } 154 155 // Delete removes VPP VRF table. 156 func (d *VrfTableDescriptor) Delete(key string, vrfTable *l3.VrfTable, metadata *vrfidx.VRFMetadata) error { 157 err := d.vtHandler.DelVrfTable(vrfTable) 158 if err != nil { 159 return err 160 } 161 162 return nil 163 } 164 165 // Retrieve returns all configured VPP VRF tables. 166 func (d *VrfTableDescriptor) Retrieve(correlate []adapter.VrfTableKVWithMetadata) ( 167 retrieved []adapter.VrfTableKVWithMetadata, err error, 168 ) { 169 tables, err := d.vtHandler.DumpVrfTables() 170 if err != nil { 171 return nil, errors.Errorf("failed to dump VPP VRF tables: %v", err) 172 } 173 174 // TODO: implement flow hash settings dump once supported by VPP (https://jira.fd.io/browse/VPP-1829) 175 // (until implemented, resync will always re-configure flow hash settings if non-default settings are used) 176 177 for _, table := range tables { 178 origin := kvs.UnknownOrigin 179 // VRF with ID=0 and ID=MaxUint32 are special 180 // and should not be removed automatically 181 if table.Id > 0 && table.Id < math.MaxUint32 { 182 origin = kvs.FromNB 183 } 184 retrieved = append(retrieved, adapter.VrfTableKVWithMetadata{ 185 Key: l3.VrfTableKey(table.Id, table.Protocol), 186 Value: table, 187 Metadata: &vrfidx.VRFMetadata{ 188 Index: table.Id, 189 Protocol: table.Protocol, 190 }, 191 Origin: origin, 192 }) 193 } 194 195 return retrieved, nil 196 } 197 198 func getVrfTableLabel(vrfTable *l3.VrfTable) string { 199 if vrfTable.Label == "" { 200 // label generated by VPP (e.g. "ipv4-VRF:0") 201 return fmt.Sprintf("%s-VRF:%d", 202 strings.ToLower(vrfTable.Protocol.String()), vrfTable.Id) 203 } 204 return vrfTable.Label 205 } 206 207 // defaultVrfFlowHashSettings returns default flow hash settings (implicitly existing if not set). 208 func defaultVrfFlowHashSettings() *l3.VrfTable_FlowHashSettings { 209 return &l3.VrfTable_FlowHashSettings{ 210 UseSrcIp: true, 211 UseDstIp: true, 212 UseSrcPort: true, 213 UseDstPort: true, 214 UseProtocol: true, 215 Symmetric: false, 216 Reverse: false, 217 } 218 }