go.ligato.io/vpp-agent/v3@v3.5.0/examples/kvscheduler/mock_plugins/l2plugin/descriptor/bridgedomain.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  	"github.com/pkg/errors"
    19  	"go.ligato.io/cn-infra/v2/idxmap"
    20  	"go.ligato.io/cn-infra/v2/logging"
    21  
    22  	ifdescriptor "go.ligato.io/vpp-agent/v3/examples/kvscheduler/mock_plugins/ifplugin/descriptor"
    23  	"go.ligato.io/vpp-agent/v3/examples/kvscheduler/mock_plugins/l2plugin/descriptor/adapter"
    24  	"go.ligato.io/vpp-agent/v3/examples/kvscheduler/mock_plugins/l2plugin/mockcalls"
    25  	l2 "go.ligato.io/vpp-agent/v3/examples/kvscheduler/mock_plugins/l2plugin/model"
    26  	"go.ligato.io/vpp-agent/v3/pkg/idxvpp"
    27  	"go.ligato.io/vpp-agent/v3/pkg/models"
    28  	kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api"
    29  )
    30  
    31  const (
    32  	// BridgeDomainDescriptorName is the name of the descriptor for mock bridge domains.
    33  	BridgeDomainDescriptorName = "mock-bridge-domain"
    34  )
    35  
    36  // Example of some validation errors:
    37  var (
    38  	// ErrBridgeDomainWithoutName is returned when mock bridge domain configuration
    39  	// has undefined Name attribute.
    40  	ErrBridgeDomainWithoutName = errors.New("mock bridge domain defined without logical name")
    41  
    42  	// ErrBridgeDomainWithMultipleBVI is returned when mock bridge domain is defined with
    43  	// multiple BVI interfaces.
    44  	ErrBridgeDomainWithMultipleBVI = errors.New("mock bridge domain defined with mutliple BVIs")
    45  )
    46  
    47  // BridgeDomainDescriptor teaches KVScheduler how to configure bridge domains
    48  // in the mock SB.
    49  type BridgeDomainDescriptor struct {
    50  	// dependencies
    51  	log       logging.Logger
    52  	bdHandler mockcalls.MockBDAPI
    53  }
    54  
    55  // NewBridgeDomainDescriptor creates a new instance of the BridgeDomain descriptor.
    56  func NewBridgeDomainDescriptor(bdHandler mockcalls.MockBDAPI, log logging.PluginLogger) *kvs.KVDescriptor {
    57  	// descriptors are supposed to be stateless and this principle is not broken
    58  	// here - we only need to keep context consisting of references to logger
    59  	// and the BD handler for mock SB, to be used inside the CRUD methods.
    60  	descrCtx := &BridgeDomainDescriptor{
    61  		bdHandler: bdHandler,
    62  		log:       log.NewLogger("mock-bd-descriptor"),
    63  	}
    64  
    65  	// use adapter to convert typed descriptor into generic descriptor API
    66  	typedDescr := &adapter.BridgeDomainDescriptor{
    67  		Name:               BridgeDomainDescriptorName,
    68  		NBKeyPrefix:        l2.ModelBridgeDomain.KeyPrefix(),
    69  		ValueTypeName:      l2.ModelBridgeDomain.ProtoName(),
    70  		KeySelector:        l2.ModelBridgeDomain.IsKeyValid,
    71  		KeyLabel:           l2.ModelBridgeDomain.StripKeyPrefix,
    72  		ValueComparator:    descrCtx.EquivalentBridgeDomains,
    73  		WithMetadata:       true,
    74  		MetadataMapFactory: descrCtx.MetadataFactory,
    75  		Validate:           descrCtx.Validate,
    76  		Create:             descrCtx.Create,
    77  		Delete:             descrCtx.Delete,
    78  
    79  		// Note: no need for Update operation - the interfaces are derived out
    80  		//       and updated as separate key-value pairs, whereas a change in
    81  		//       the Name actually results in a different key and creates a new
    82  		//       BD altogether.
    83  
    84  		Retrieve:      descrCtx.Retrieve,
    85  		DerivedValues: descrCtx.DerivedValues,
    86  
    87  		// Retrieve interfaces first to have the index with interface metadata
    88  		// up-to-date when Retrieve for bridge domains is called, which then uses
    89  		// the index to translate interface names to the corresponding integer
    90  		// handles used in the mock SB.
    91  		RetrieveDependencies: []string{ifdescriptor.InterfaceDescriptorName},
    92  	}
    93  	return adapter.NewBridgeDomainDescriptor(typedDescr)
    94  }
    95  
    96  // EquivalentBridgeDomains always returns true - this may seems strange, but
    97  // two revisions of the same BD have the same key, therefore they must equal
    98  // in Name, which is included in the key. The interfaces may differ, but
    99  // they are derived out and updated as separate key-value pairs.
   100  func (d *BridgeDomainDescriptor) EquivalentBridgeDomains(key string, oldBD, newBD *l2.BridgeDomain) bool {
   101  	return true
   102  }
   103  
   104  // MetadataFactory is a factory for index-map customized for mock bridge domains.
   105  func (d *BridgeDomainDescriptor) MetadataFactory() idxmap.NamedMappingRW {
   106  	return idxvpp.NewNameToIndex(d.log, "mock-bd-index", nil)
   107  }
   108  
   109  // Validate validates mock bridge domain configuration.
   110  func (d *BridgeDomainDescriptor) Validate(key string, bd *l2.BridgeDomain) error {
   111  	if bd.Name == "" {
   112  		return kvs.NewInvalidValueError(ErrBridgeDomainWithoutName, "name")
   113  	}
   114  
   115  	// check that BD has defined at most one BVI
   116  	var hasBVI bool
   117  	for _, bdIface := range bd.Interfaces {
   118  		if bdIface.BridgedVirtualInterface {
   119  			if hasBVI {
   120  				return kvs.NewInvalidValueError(ErrBridgeDomainWithMultipleBVI,
   121  					"interfaces.bridged_virtual_interface")
   122  			}
   123  			hasBVI = true
   124  		}
   125  	}
   126  	return nil
   127  }
   128  
   129  // Create adds new bridge domain.
   130  func (d *BridgeDomainDescriptor) Create(key string, bd *l2.BridgeDomain) (metadata *idxvpp.OnlyIndex, err error) {
   131  	sbBDHandle, err := d.bdHandler.CreateBridgeDomain(bd.Name)
   132  	if err != nil {
   133  		d.log.Error(err)
   134  		return nil, err
   135  	}
   136  
   137  	// fill the metadata and return
   138  	metadata = &idxvpp.OnlyIndex{
   139  		Index: sbBDHandle,
   140  	}
   141  	return metadata, nil
   142  }
   143  
   144  // Delete removes VPP bridge domain.
   145  func (d *BridgeDomainDescriptor) Delete(key string, bd *l2.BridgeDomain, metadata *idxvpp.OnlyIndex) error {
   146  	err := d.bdHandler.DeleteBridgeDomain(metadata.GetIndex())
   147  	if err != nil {
   148  		d.log.Error(err)
   149  	}
   150  	return err
   151  }
   152  
   153  // Retrieve returns all configured mock bridge domains.
   154  func (d *BridgeDomainDescriptor) Retrieve(correlate []adapter.BridgeDomainKVWithMetadata) (retrieved []adapter.BridgeDomainKVWithMetadata, err error) {
   155  	bds, err := d.bdHandler.DumpBridgeDomains()
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  
   160  	for sbBDHandle, bd := range bds {
   161  		retrieved = append(retrieved, adapter.BridgeDomainKVWithMetadata{
   162  			Key:      models.Key(bd),
   163  			Value:    bd,
   164  			Metadata: &idxvpp.OnlyIndex{Index: sbBDHandle},
   165  			Origin:   kvs.FromNB, // not considering OBTAINED BDs in our simplified example
   166  		})
   167  	}
   168  	return retrieved, nil
   169  }
   170  
   171  // DerivedValues derives l2.BridgeDomain_Interface for every interface assigned
   172  // to the bridge domain.
   173  func (d *BridgeDomainDescriptor) DerivedValues(key string, bd *l2.BridgeDomain) (derValues []kvs.KeyValuePair) {
   174  	// BD interfaces
   175  	for _, bdIface := range bd.Interfaces {
   176  		derValues = append(derValues, kvs.KeyValuePair{
   177  			Key:   l2.BDInterfaceKey(bd.Name, bdIface.Name),
   178  			Value: bdIface,
   179  		})
   180  	}
   181  	return derValues
   182  }