go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/ifplugin/descriptor/span.go (about)

     1  // Copyright (c) 2019 PANTHEON.tech
     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  	"go.ligato.io/cn-infra/v2/logging"
    20  
    21  	kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api"
    22  	"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/descriptor/adapter"
    23  	"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/ifaceidx"
    24  	"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/vppcalls"
    25  	interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces"
    26  )
    27  
    28  const (
    29  	// SpanDescriptorName is the name of the descriptor.
    30  	SpanDescriptorName = "vpp-span"
    31  )
    32  
    33  // A list of non-retriable errors:
    34  var (
    35  	ErrSpanWithoutInterface = errors.New("VPP SPAN defined without From/To interface")
    36  	ErrSpanWithoutDirection = errors.New("VPP SPAN defined without direction (Rx, Tx or Both)")
    37  )
    38  
    39  // SpanDescriptor teaches KVScheduler how to configure VPP SPAN.
    40  type SpanDescriptor struct {
    41  	log         logging.Logger
    42  	spanHandler vppcalls.InterfaceVppAPI
    43  	intfIndex   ifaceidx.IfaceMetadataIndex
    44  }
    45  
    46  // NewSpanDescriptor creates a new instance of the SpanDescriptor.
    47  func NewSpanDescriptor(spanHandler vppcalls.InterfaceVppAPI, log logging.PluginLogger) (*kvs.KVDescriptor, *SpanDescriptor) {
    48  
    49  	ctx := &SpanDescriptor{
    50  		spanHandler: spanHandler,
    51  		log:         log.NewLogger("span-descriptor"),
    52  	}
    53  
    54  	typedDescr := &adapter.SpanDescriptor{
    55  		Name:                 SpanDescriptorName,
    56  		KeySelector:          interfaces.ModelSpan.IsKeyValid,
    57  		KeyLabel:             interfaces.ModelSpan.StripKeyPrefix,
    58  		NBKeyPrefix:          interfaces.ModelSpan.KeyPrefix(),
    59  		ValueTypeName:        interfaces.ModelSpan.ProtoName(),
    60  		Create:               ctx.Create,
    61  		Delete:               ctx.Delete,
    62  		Retrieve:             ctx.Retrieve,
    63  		Validate:             ctx.Validate,
    64  		Dependencies:         ctx.Dependencies,
    65  		RetrieveDependencies: []string{InterfaceDescriptorName},
    66  	}
    67  
    68  	return adapter.NewSpanDescriptor(typedDescr), ctx
    69  }
    70  
    71  // SetInterfaceIndex should be used to provide interface index immediately after
    72  // the descriptor registration.
    73  func (d *SpanDescriptor) SetInterfaceIndex(intfIndex ifaceidx.IfaceMetadataIndex) {
    74  	d.intfIndex = intfIndex
    75  }
    76  
    77  // Validate checks if required filed are not empty.
    78  func (d *SpanDescriptor) Validate(key string, value *interfaces.Span) error {
    79  	if value.InterfaceFrom == "" && value.InterfaceTo == "" {
    80  		return kvs.NewInvalidValueError(ErrSpanWithoutInterface,
    81  			"interface_from", "interface_to")
    82  	}
    83  	if value.InterfaceFrom == "" {
    84  		return kvs.NewInvalidValueError(ErrSpanWithoutInterface, "interface_from")
    85  	}
    86  	if value.InterfaceTo == "" {
    87  		return kvs.NewInvalidValueError(ErrSpanWithoutInterface, "interface_to")
    88  	}
    89  	if value.Direction == interfaces.Span_UNKNOWN {
    90  		return kvs.NewInvalidValueError(ErrSpanWithoutDirection, "direction")
    91  	}
    92  	return nil
    93  }
    94  
    95  // Create configures SPAN.
    96  func (d *SpanDescriptor) Create(key string, value *interfaces.Span) (metadata interface{}, err error) {
    97  	ifaceFrom, found := d.intfIndex.LookupByName(value.InterfaceFrom)
    98  	if !found {
    99  		err = errors.Errorf("failed to find InterfaceFrom %s", value.InterfaceFrom)
   100  		d.log.Error(err)
   101  		return nil, err
   102  	}
   103  
   104  	ifaceTo, found := d.intfIndex.LookupByName(value.InterfaceTo)
   105  	if !found {
   106  		err = errors.Errorf("failed to find InterfaceTo %s", value.InterfaceTo)
   107  		d.log.Error(err)
   108  		return nil, err
   109  	}
   110  
   111  	err = d.spanHandler.AddSpan(ifaceFrom.SwIfIndex, ifaceTo.SwIfIndex, uint8(value.Direction), value.IsL2)
   112  	if err != nil {
   113  		err = errors.Errorf("failed to add interface span: %v", err)
   114  		d.log.Error(err)
   115  		return nil, err
   116  	}
   117  
   118  	return nil, err
   119  }
   120  
   121  // Delete removes SPAN.
   122  func (d *SpanDescriptor) Delete(key string, value *interfaces.Span, metadata interface{}) error {
   123  	var err error
   124  	ifaceFrom, found := d.intfIndex.LookupByName(value.InterfaceFrom)
   125  	if !found {
   126  		err = errors.Errorf("failed to find InterfaceFrom %s", value.InterfaceFrom)
   127  		d.log.Error(err)
   128  		return err
   129  	}
   130  
   131  	ifaceTo, found := d.intfIndex.LookupByName(value.InterfaceTo)
   132  	if !found {
   133  		err = errors.Errorf("failed to find InterfaceTo %s", value.InterfaceTo)
   134  		d.log.Error(err)
   135  		return err
   136  	}
   137  
   138  	err = d.spanHandler.DelSpan(ifaceFrom.SwIfIndex, ifaceTo.SwIfIndex, value.IsL2)
   139  	if err != nil {
   140  		err = errors.Errorf("failed to delete interface span: %v", err)
   141  		d.log.Error(err)
   142  		return err
   143  	}
   144  
   145  	return err
   146  }
   147  
   148  // Retrieve returns all records from VPP SPAN table.
   149  func (d *SpanDescriptor) Retrieve(correlate []adapter.SpanKVWithMetadata) (retrieved []adapter.SpanKVWithMetadata, err error) {
   150  	spans, err := d.spanHandler.DumpSpan()
   151  	if err != nil {
   152  		d.log.Error(err)
   153  		return retrieved, err
   154  	}
   155  
   156  	var nameFrom, nameTo string
   157  	var exists bool
   158  	for _, s := range spans {
   159  		nameFrom, _, exists = d.intfIndex.LookupBySwIfIndex(s.SwIfIndexFrom)
   160  		if !exists {
   161  			d.log.Debugf("failed to find interface with index %d", s.SwIfIndexFrom)
   162  			continue
   163  		}
   164  		nameTo, _, exists = d.intfIndex.LookupBySwIfIndex(s.SwIfIndexTo)
   165  		if !exists {
   166  			d.log.Debugf("failed to find interface with index %d", s.SwIfIndexTo)
   167  			continue
   168  		}
   169  		retrieved = append(retrieved, adapter.SpanKVWithMetadata{
   170  			Key: interfaces.SpanKey(nameFrom, nameTo),
   171  			Value: &interfaces.Span{
   172  				InterfaceFrom: nameFrom,
   173  				InterfaceTo:   nameTo,
   174  				Direction:     interfaces.Span_Direction(s.Direction),
   175  				IsL2:          s.IsL2,
   176  			},
   177  			Origin: kvs.FromNB,
   178  		})
   179  	}
   180  	return retrieved, nil
   181  }
   182  
   183  // Dependencies lists both From and To interfaces as dependencies.
   184  func (d *SpanDescriptor) Dependencies(key string, value *interfaces.Span) []kvs.Dependency {
   185  	return []kvs.Dependency{
   186  		{
   187  			Label: "interface-from",
   188  			Key:   interfaces.InterfaceKey(value.InterfaceFrom),
   189  		},
   190  		{
   191  			Label: "interface-to",
   192  			Key:   interfaces.InterfaceKey(value.InterfaceTo),
   193  		},
   194  	}
   195  }