go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/binapi/binapi.go (about)

     1  //  Copyright (c) 2019 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 binapi
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  
    21  	govppapi "go.fd.io/govpp/api"
    22  	"go.ligato.io/cn-infra/v2/logging"
    23  )
    24  
    25  // Versions is a map of all binapi messages for each supported VPP versions.
    26  var Versions = map[Version]VersionMsgs{}
    27  
    28  type CompatibilityChecker interface {
    29  	// CheckCompatiblity checks compatibility with given binapi messages.
    30  	CheckCompatiblity(...govppapi.Message) error
    31  }
    32  
    33  func CompatibleVersion(ch CompatibilityChecker) (Version, error) {
    34  	if len(Versions) == 0 {
    35  		return "", fmt.Errorf("no binapi versions loaded")
    36  	}
    37  	var picked = struct {
    38  		version      Version
    39  		incompatible int
    40  	}{}
    41  	for version, check := range Versions {
    42  		var compErr *govppapi.CompatibilityError
    43  
    44  		// check core compatibility
    45  		coreMsgs := check.Core.AllMessages()
    46  		if err := ch.CheckCompatiblity(coreMsgs...); errors.As(err, &compErr) {
    47  			logging.Debugf("binapi version %v core incompatible (%d/%d messages)", version, len(compErr.IncompatibleMessages), len(coreMsgs))
    48  			continue
    49  		} else if err != nil {
    50  			logging.Warnf("binapi version %v check failed: %v", version, err)
    51  			continue
    52  		}
    53  
    54  		// check plugins compatibility
    55  		pluginMsgs := check.Plugins.AllMessages()
    56  		if err := ch.CheckCompatiblity(pluginMsgs...); errors.As(err, &compErr) {
    57  			// some plugins might be disabled
    58  			logging.Debugf("binapi version %v partly incompatible: (%d/%d messages)", version, len(compErr.IncompatibleMessages), len(pluginMsgs))
    59  			if picked.version == "" || picked.incompatible > len(compErr.IncompatibleMessages) {
    60  				picked.version = version
    61  				picked.incompatible = len(compErr.IncompatibleMessages)
    62  			}
    63  		} else if err != nil {
    64  			logging.Warnf("binapi version %v check failed: %v", version, err)
    65  		} else {
    66  			logging.Debugf("binapi version %v fully COMPATIBLE (%d messages)", version, len(coreMsgs)+len(pluginMsgs))
    67  			return version, nil
    68  		}
    69  	}
    70  	if picked.version != "" {
    71  		logging.Debugf("choosing the most compatible binapi version: %v", picked.version)
    72  		return picked.version, nil
    73  	}
    74  	return "", fmt.Errorf("no compatible binapi version found")
    75  }
    76  
    77  // VersionMsgs contains list of messages in version.
    78  type VersionMsgs struct {
    79  	Core    MessagesList
    80  	Plugins MessagesList
    81  }
    82  
    83  // AllMessages returns messages from message list funcs combined.
    84  func (vc VersionMsgs) AllMessages() []govppapi.Message {
    85  	var msgs []govppapi.Message
    86  	msgs = append(msgs, vc.Core.AllMessages()...)
    87  	msgs = append(msgs, vc.Plugins.AllMessages()...)
    88  	return msgs
    89  }
    90  
    91  // Version represents VPP version for generated binapi.
    92  type Version string
    93  
    94  // MessagesList aggregates multiple funcs that return messages.
    95  type MessagesList []func() []govppapi.Message
    96  
    97  // Messages is used to initialize message list.
    98  func Messages(funcs ...func() []govppapi.Message) MessagesList {
    99  	var list MessagesList
   100  	list.Add(funcs...)
   101  	return list
   102  }
   103  
   104  // Add adds funcs to message list.
   105  func (list *MessagesList) Add(funcs ...func() []govppapi.Message) {
   106  	for _, msgFunc := range funcs {
   107  		*list = append(*list, msgFunc)
   108  	}
   109  }
   110  
   111  // AllMessages returns messages from message list funcs combined.
   112  func (list *MessagesList) AllMessages() []govppapi.Message {
   113  	var msgs []govppapi.Message
   114  	for _, msgFunc := range *list {
   115  		msgs = append(msgs, msgFunc()...)
   116  	}
   117  	return msgs
   118  }