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  }