go.ligato.io/vpp-agent/v3@v3.5.0/examples/govpp_call/main.go (about)

     1  // Copyright (c) 2017 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 main
    16  
    17  import (
    18  	"log"
    19  	"time"
    20  
    21  	govppapi "go.fd.io/govpp/api"
    22  	"go.ligato.io/cn-infra/v2/agent"
    23  	"go.ligato.io/cn-infra/v2/logging"
    24  	"go.ligato.io/cn-infra/v2/logging/logrus"
    25  	"go.ligato.io/cn-infra/v2/utils/safeclose"
    26  
    27  	"go.ligato.io/vpp-agent/v3/cmd/vpp-agent/app"
    28  	"go.ligato.io/vpp-agent/v3/plugins/govppmux"
    29  	l2Api "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/l2"
    30  	l2 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l2"
    31  )
    32  
    33  // *************************************************************************
    34  // This file contains examples of GOVPP operations, conversion of a proto
    35  // data to a binary api message and demonstration of sending the message
    36  // to the VPP with:
    37  //
    38  // requestContext = goVppChannel.SendRequest(requestMessage)
    39  // requestContext.ReceiveReply(replyMessage)
    40  //
    41  // Note: this example shows how to work with VPP, so real proto message
    42  // structure is used (bridge domains).
    43  // ************************************************************************/
    44  
    45  // Main allows running Example Plugin as a statically linked binary with Agent Core Plugins. Close channel and plugins
    46  // required for the example are initialized. Agent is instantiated with generic plugins (etcd, Kafka, Status check,
    47  // HTTP and Log), and GOVPP, and resync plugin, and example plugin which demonstrates GOVPP call functionality.
    48  func main() {
    49  	// Init close channel to stop the example.
    50  	closeChannel := make(chan struct{})
    51  
    52  	// Inject dependencies to example plugin
    53  	ep := &ExamplePlugin{
    54  		Log:          logrus.DefaultLogger(),
    55  		closeChannel: closeChannel,
    56  	}
    57  	ep.Deps.VPP = app.DefaultVPP()
    58  	ep.Deps.GoVppMux = &govppmux.DefaultPlugin
    59  
    60  	// Start Agent
    61  	a := agent.NewAgent(
    62  		agent.AllPlugins(ep),
    63  		agent.QuitOnClose(closeChannel),
    64  	)
    65  	if err := a.Run(); err != nil {
    66  		log.Fatal()
    67  	}
    68  }
    69  
    70  // PluginName represents name of plugin.
    71  const PluginName = "govpp-example"
    72  
    73  // ExamplePlugin implements Plugin interface which is used to pass custom plugin instances to the Agent.
    74  type ExamplePlugin struct {
    75  	Deps
    76  
    77  	exampleIDSeq uint32           // Plugin-specific ID initialization
    78  	vppChannel   govppapi.Channel // Vpp channel to communicate with VPP
    79  	// Fields below are used to properly finish the example.
    80  	closeChannel chan struct{}
    81  	Log          logging.Logger
    82  }
    83  
    84  // Deps is example plugin dependencies.
    85  type Deps struct {
    86  	GoVppMux *govppmux.Plugin
    87  	VPP      app.VPP
    88  }
    89  
    90  // Init members of plugin.
    91  func (plugin *ExamplePlugin) Init() (err error) {
    92  	// NewAPIChannel returns a new API channel for communication with VPP via govpp core.
    93  	// It uses default buffer sizes for the request and reply Go channels.
    94  	plugin.vppChannel, err = plugin.Deps.GoVppMux.NewAPIChannel()
    95  
    96  	plugin.Log.Info("Default plugin plugin ready")
    97  
    98  	// Make VPP call
    99  	go plugin.VppCall()
   100  
   101  	return err
   102  }
   103  
   104  // Close is called by Agent Core when the Agent is shutting down. It is supposed
   105  // to clean up resources that were allocated by the plugin during its lifetime.
   106  func (plugin *ExamplePlugin) Close() error {
   107  	return safeclose.Close(plugin.vppChannel)
   108  }
   109  
   110  // String returns plugin name
   111  func (plugin *ExamplePlugin) String() string {
   112  	return PluginName
   113  }
   114  
   115  /***********
   116   * VPPCall *
   117   ***********/
   118  
   119  // VppCall uses created data to convert it to the binary api call. In the example,
   120  // a bridge domain data are built and transformed to the BridgeDomainAddDel binary api call
   121  // which is then sent to the VPP.
   122  func (plugin *ExamplePlugin) VppCall() {
   123  	time.Sleep(3 * time.Second)
   124  
   125  	// Prepare a simple data.
   126  	plugin.Log.Info("Preparing data ...")
   127  	bds1 := buildData("br1")
   128  	bds2 := buildData("br2")
   129  	bds3 := buildData("br3")
   130  
   131  	// Prepare binary api message from the data.
   132  	req1 := buildBinapiMessage(bds1, plugin.exampleIDSeq)
   133  	plugin.exampleIDSeq++ // Change (raise) index to ensure every message uses unique ID.
   134  	req2 := buildBinapiMessage(bds2, plugin.exampleIDSeq)
   135  	plugin.exampleIDSeq++
   136  	req3 := buildBinapiMessage(bds3, plugin.exampleIDSeq)
   137  	plugin.exampleIDSeq++
   138  
   139  	// Generic bin api reply (request: BridgeDomainAddDel)
   140  	reply := &l2Api.BridgeDomainAddDelReply{}
   141  
   142  	plugin.Log.Info("Sending data to VPP ...")
   143  
   144  	// 1. Send the request and receive a reply directly (in one line).
   145  	plugin.vppChannel.SendRequest(req1).ReceiveReply(reply)
   146  
   147  	// 2. Send multiple different requests. Every request returns it's own request context.
   148  	reqCtx2 := plugin.vppChannel.SendRequest(req2)
   149  	reqCtx3 := plugin.vppChannel.SendRequest(req3)
   150  	// The context can be used later to get reply.
   151  	reqCtx2.ReceiveReply(reply)
   152  	reqCtx3.ReceiveReply(reply)
   153  
   154  	plugin.Log.Info("Data successfully sent to VPP")
   155  	// End the example.
   156  	plugin.Log.Infof("etcd/datasync example finished, sending shutdown ...")
   157  	close(plugin.closeChannel)
   158  }
   159  
   160  // Auxiliary function to build bridge domain data
   161  func buildData(name string) *l2.BridgeDomain {
   162  	return &l2.BridgeDomain{
   163  		Name:                name,
   164  		Flood:               false,
   165  		UnknownUnicastFlood: true,
   166  		Forward:             true,
   167  		Learn:               true,
   168  		ArpTermination:      true,
   169  		MacAge:              0,
   170  		Interfaces: []*l2.BridgeDomain_Interface{
   171  			{
   172  				Name: "memif1",
   173  			},
   174  		},
   175  	}
   176  }
   177  
   178  // Auxiliary method to transform agent model data to binary api format
   179  func buildBinapiMessage(data *l2.BridgeDomain, id uint32) *l2Api.BridgeDomainAddDel {
   180  	req := &l2Api.BridgeDomainAddDel{}
   181  	req.IsAdd = true
   182  	req.BdID = id
   183  	req.Flood = data.Flood
   184  	req.UuFlood = data.UnknownUnicastFlood
   185  	req.Forward = data.Forward
   186  	req.Learn = data.Learn
   187  	req.ArpTerm = data.ArpTermination
   188  	req.MacAge = uint8(data.MacAge)
   189  
   190  	return req
   191  }