go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/ifplugin/vppcalls/vpp2106/memif_vppcalls.go (about)

     1  //  Copyright (c) 2021 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 vpp2106
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"io"
    21  	"strings"
    22  
    23  	"github.com/pkg/errors"
    24  	"go.fd.io/govpp/api"
    25  
    26  	"go.ligato.io/vpp-agent/v3/plugins/vpp"
    27  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/interface_types"
    28  	vpp_memif "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/memif"
    29  	"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/vppcalls"
    30  	ifs "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces"
    31  )
    32  
    33  func (h *InterfaceVppHandler) AddMemifInterface(ctx context.Context, ifName string, memIface *ifs.MemifLink, socketID uint32) (swIdx uint32, err error) {
    34  	if h.memif == nil {
    35  		return 0, errors.WithMessage(vpp.ErrPluginDisabled, "memif")
    36  	}
    37  
    38  	req := &vpp_memif.MemifCreate{
    39  		ID:         memIface.Id,
    40  		Mode:       memifMode(memIface.Mode),
    41  		Secret:     memIface.Secret,
    42  		SocketID:   socketID,
    43  		BufferSize: uint16(memIface.BufferSize),
    44  		RingSize:   memIface.RingSize,
    45  		RxQueues:   uint8(memIface.RxQueues),
    46  		TxQueues:   uint8(memIface.TxQueues),
    47  	}
    48  	if memIface.Master {
    49  		req.Role = 0
    50  	} else {
    51  		req.Role = 1
    52  	}
    53  	// TODO: temporary fix, waiting for https://gerrit.fd.io/r/#/c/7266/
    54  	if req.RxQueues == 0 {
    55  		req.RxQueues = 1
    56  	}
    57  	if req.TxQueues == 0 {
    58  		req.TxQueues = 1
    59  	}
    60  
    61  	reply, err := h.memif.MemifCreate(ctx, req)
    62  	if err != nil {
    63  		return 0, err
    64  	} else if err = api.RetvalToVPPApiError(reply.Retval); err != nil {
    65  		return 0, err
    66  	}
    67  	swIdx = uint32(reply.SwIfIndex)
    68  
    69  	return swIdx, h.SetInterfaceTag(ifName, swIdx)
    70  }
    71  
    72  func (h *InterfaceVppHandler) DeleteMemifInterface(ctx context.Context, ifName string, idx uint32) error {
    73  	if h.memif == nil {
    74  		return errors.WithMessage(vpp.ErrPluginDisabled, "memif")
    75  	}
    76  
    77  	req := &vpp_memif.MemifDelete{
    78  		SwIfIndex: interface_types.InterfaceIndex(idx),
    79  	}
    80  	if reply, err := h.memif.MemifDelete(ctx, req); err != nil {
    81  		return err
    82  	} else if err = api.RetvalToVPPApiError(reply.Retval); err != nil {
    83  		return err
    84  	}
    85  
    86  	return h.RemoveInterfaceTag(ifName, idx)
    87  }
    88  
    89  func (h *InterfaceVppHandler) RegisterMemifSocketFilename(ctx context.Context, filename string, id uint32) error {
    90  	if h.memif == nil {
    91  		return errors.WithMessage(vpp.ErrPluginDisabled, "memif")
    92  	}
    93  
    94  	req := &vpp_memif.MemifSocketFilenameAddDel{
    95  		SocketFilename: filename,
    96  		SocketID:       id,
    97  		IsAdd:          true, // sockets can be added only
    98  	}
    99  	if reply, err := h.memif.MemifSocketFilenameAddDel(ctx, req); err != nil {
   100  		return err
   101  	} else if err = api.RetvalToVPPApiError(reply.Retval); err != nil {
   102  		return err
   103  	}
   104  	return nil
   105  }
   106  
   107  func memifMode(mode ifs.MemifLink_MemifMode) vpp_memif.MemifMode {
   108  	switch mode {
   109  	case ifs.MemifLink_IP:
   110  		return vpp_memif.MEMIF_MODE_API_IP
   111  	case ifs.MemifLink_PUNT_INJECT:
   112  		return vpp_memif.MEMIF_MODE_API_PUNT_INJECT
   113  	default:
   114  		return vpp_memif.MEMIF_MODE_API_ETHERNET
   115  	}
   116  }
   117  
   118  func (h *InterfaceVppHandler) DumpMemifSocketDetails(ctx context.Context) (map[string]uint32, error) {
   119  	if h.memif == nil {
   120  		return nil, errors.WithMessage(vpp.ErrPluginDisabled, "memif")
   121  	}
   122  
   123  	dump, err := h.memif.MemifSocketFilenameDump(ctx, &vpp_memif.MemifSocketFilenameDump{})
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	memifSocketMap := make(map[string]uint32)
   128  	for {
   129  		socketDetails, err := dump.Recv()
   130  		if err == io.EOF {
   131  			break
   132  		}
   133  		if err != nil {
   134  			return nil, err
   135  		}
   136  
   137  		filename := strings.SplitN(socketDetails.SocketFilename, "\x00", 2)[0]
   138  		memifSocketMap[filename] = socketDetails.SocketID
   139  	}
   140  
   141  	h.log.Debugf("Memif socket dump completed, found %d entries: %v", len(memifSocketMap), memifSocketMap)
   142  
   143  	return memifSocketMap, nil
   144  }
   145  
   146  // dumpMemifDetails dumps memif interface details from VPP and fills them into the provided interface map.
   147  func (h *InterfaceVppHandler) dumpMemifDetails(ctx context.Context, interfaces map[uint32]*vppcalls.InterfaceDetails) error {
   148  	if h.memif == nil {
   149  		// no-op when disabled
   150  		return nil
   151  	}
   152  
   153  	memifSocketMap, err := h.DumpMemifSocketDetails(ctx)
   154  	if err != nil {
   155  		return fmt.Errorf("dumping memif socket details failed: %v", err)
   156  	}
   157  
   158  	dump, err := h.memif.MemifDump(ctx, &vpp_memif.MemifDump{})
   159  	if err != nil {
   160  		return err
   161  	}
   162  	for {
   163  		memifDetails, err := dump.Recv()
   164  		if err == io.EOF {
   165  			break
   166  		}
   167  		if err != nil {
   168  			return err
   169  		}
   170  
   171  		_, ifIdxExists := interfaces[uint32(memifDetails.SwIfIndex)]
   172  		if !ifIdxExists {
   173  			continue
   174  		}
   175  		interfaces[uint32(memifDetails.SwIfIndex)].Interface.Link = &ifs.Interface_Memif{
   176  			Memif: &ifs.MemifLink{
   177  				Master: memifDetails.Role == 0,
   178  				Mode:   memifModetoNB(memifDetails.Mode),
   179  				Id:     memifDetails.ID,
   180  				// Secret: // TODO: Secret - not available in the binary API
   181  				SocketFilename: func(socketMap map[string]uint32) (filename string) {
   182  					for filename, id := range socketMap {
   183  						if memifDetails.SocketID == id {
   184  							return filename
   185  						}
   186  					}
   187  					// Socket for configured memif should exist
   188  					h.log.Warnf("Socket ID not found for memif %v", memifDetails.SwIfIndex)
   189  					return
   190  				}(memifSocketMap),
   191  				RingSize:   memifDetails.RingSize,
   192  				BufferSize: uint32(memifDetails.BufferSize),
   193  				// TODO: RxQueues, TxQueues - not available in the binary API
   194  				// RxQueues:
   195  				// TxQueues:
   196  			},
   197  		}
   198  		interfaces[uint32(memifDetails.SwIfIndex)].Interface.Type = ifs.Interface_MEMIF
   199  	}
   200  
   201  	return nil
   202  }