go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/abfplugin/vppcalls/vpp2101/abf_vppcalls.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 vpp2101
    16  
    17  import (
    18  	"fmt"
    19  	"net"
    20  
    21  	"github.com/go-errors/errors"
    22  
    23  	vpp_abf "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/abf"
    24  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/fib_types"
    25  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/interface_types"
    26  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/ip_types"
    27  	abf "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/abf"
    28  )
    29  
    30  const (
    31  	// NextHopViaLabelUnset constant has to be assigned into the field next hop  via label
    32  	// in abf_policy_add_del binary message if next hop via label is not defined.
    33  	NextHopViaLabelUnset uint32 = 0xfffff + 1
    34  
    35  	// ClassifyTableIndexUnset is a default value for field classify_table_index
    36  	// in abf_policy_add_del binary message.
    37  	ClassifyTableIndexUnset = ^uint32(0)
    38  )
    39  
    40  // GetAbfVersion retrieves version of the VPP ABF plugin
    41  func (h *ABFVppHandler) GetAbfVersion() (ver string, err error) {
    42  	req := &vpp_abf.AbfPluginGetVersion{}
    43  	reply := &vpp_abf.AbfPluginGetVersionReply{}
    44  
    45  	if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
    46  		return "", err
    47  	}
    48  
    49  	return fmt.Sprintf("%d.%d", reply.Major, reply.Minor), nil
    50  }
    51  
    52  // AddAbfPolicy creates new ABF entry together with a list of forwarding paths
    53  func (h *ABFVppHandler) AddAbfPolicy(policyID, aclID uint32, abfPaths []*abf.ABF_ForwardingPath) error {
    54  	if err := h.abfAddDelPolicy(policyID, aclID, abfPaths, true); err != nil {
    55  		return errors.Errorf("failed to add ABF policy %d (ACL: %v): %v", policyID, aclID, err)
    56  	}
    57  	return nil
    58  }
    59  
    60  // DeleteAbfPolicy removes existing ABF entry
    61  func (h *ABFVppHandler) DeleteAbfPolicy(policyID uint32, abfPaths []*abf.ABF_ForwardingPath) error {
    62  	if err := h.abfAddDelPolicy(policyID, 0, abfPaths, false); err != nil {
    63  		return errors.Errorf("failed to delete ABF policy %d: %v", policyID, err)
    64  	}
    65  	return nil
    66  }
    67  
    68  // AbfAttachInterfaceIPv4 attaches IPv4 interface to the ABF
    69  func (h *ABFVppHandler) AbfAttachInterfaceIPv4(policyID, ifIdx, priority uint32) error {
    70  	if err := h.abfAttachDetachInterface(policyID, ifIdx, priority, true, false); err != nil {
    71  		return errors.Errorf("failed to attach IPv4 interface %d to ABF policy %d: %v", ifIdx, policyID, err)
    72  	}
    73  	return nil
    74  }
    75  
    76  // AbfDetachInterfaceIPv4 detaches IPV4 interface from the ABF
    77  func (h *ABFVppHandler) AbfDetachInterfaceIPv4(policyID, ifIdx, priority uint32) error {
    78  	if err := h.abfAttachDetachInterface(policyID, ifIdx, priority, false, false); err != nil {
    79  		return errors.Errorf("failed to detach IPv4 interface %d from ABF policy %d: %v", ifIdx, policyID, err)
    80  	}
    81  	return nil
    82  }
    83  
    84  // AbfAttachInterfaceIPv6 attaches IPv6 interface to the ABF
    85  func (h *ABFVppHandler) AbfAttachInterfaceIPv6(policyID, ifIdx, priority uint32) error {
    86  	if err := h.abfAttachDetachInterface(policyID, ifIdx, priority, true, true); err != nil {
    87  		return errors.Errorf("failed to attach IPv6 interface %d to ABF policy %d: %v", ifIdx, policyID, err)
    88  	}
    89  	return nil
    90  }
    91  
    92  // AbfDetachInterfaceIPv6 detaches IPv6 interface from the ABF
    93  func (h *ABFVppHandler) AbfDetachInterfaceIPv6(policyID, ifIdx, priority uint32) error {
    94  	if err := h.abfAttachDetachInterface(policyID, ifIdx, priority, false, true); err != nil {
    95  		return errors.Errorf("failed to detach IPv6 interface %d from ABF policy %d: %v", ifIdx, policyID, err)
    96  	}
    97  	return nil
    98  }
    99  
   100  func (h *ABFVppHandler) abfAttachDetachInterface(policyID, ifIdx, priority uint32, isAdd, isIPv6 bool) error {
   101  	req := &vpp_abf.AbfItfAttachAddDel{
   102  		IsAdd: isAdd,
   103  		Attach: vpp_abf.AbfItfAttach{
   104  			PolicyID:  policyID,
   105  			SwIfIndex: interface_types.InterfaceIndex(ifIdx),
   106  			Priority:  priority,
   107  			IsIPv6:    isIPv6,
   108  		},
   109  	}
   110  	reply := &vpp_abf.AbfItfAttachAddDelReply{}
   111  
   112  	return h.callsChannel.SendRequest(req).ReceiveReply(reply)
   113  }
   114  
   115  func (h *ABFVppHandler) abfAddDelPolicy(policyID, aclID uint32, abfPaths []*abf.ABF_ForwardingPath, isAdd bool) error {
   116  	req := &vpp_abf.AbfPolicyAddDel{
   117  		IsAdd: isAdd,
   118  		Policy: vpp_abf.AbfPolicy{
   119  			PolicyID: policyID,
   120  			ACLIndex: aclID,
   121  			Paths:    h.toFibPaths(abfPaths),
   122  			NPaths:   uint8(len(abfPaths)),
   123  		},
   124  	}
   125  	reply := &vpp_abf.AbfPolicyAddDelReply{}
   126  
   127  	return h.callsChannel.SendRequest(req).ReceiveReply(reply)
   128  }
   129  
   130  func (h *ABFVppHandler) toFibPaths(abfPaths []*abf.ABF_ForwardingPath) (fibPaths []fib_types.FibPath) {
   131  	var err error
   132  	for _, abfPath := range abfPaths {
   133  		// fib path interface
   134  		ifData, exists := h.ifIndexes.LookupByName(abfPath.InterfaceName)
   135  		if !exists {
   136  			continue
   137  		}
   138  
   139  		fibPath := fib_types.FibPath{
   140  			SwIfIndex:  ifData.SwIfIndex,
   141  			Weight:     uint8(abfPath.Weight),
   142  			Preference: uint8(abfPath.Preference),
   143  			Type:       setFibPathType(abfPath.Dvr),
   144  		}
   145  		if fibPath.Nh, fibPath.Proto, err = setFibPathNhAndProto(abfPath.NextHopIp); err != nil {
   146  			h.log.Errorf("ABF path next hop error: %v", err)
   147  		}
   148  		fibPaths = append(fibPaths, fibPath)
   149  	}
   150  
   151  	return fibPaths
   152  }
   153  
   154  // supported cases are DVR and normal
   155  func setFibPathType(isDvr bool) fib_types.FibPathType {
   156  	if isDvr {
   157  		return fib_types.FIB_API_PATH_TYPE_DVR
   158  	}
   159  	return fib_types.FIB_API_PATH_TYPE_NORMAL
   160  }
   161  
   162  // resolve IP address and return FIB path next hop (IP address) and IPv4/IPv6 version
   163  func setFibPathNhAndProto(ipStr string) (nh fib_types.FibPathNh, proto fib_types.FibPathNhProto, err error) {
   164  	netIP := net.ParseIP(ipStr)
   165  	if netIP == nil {
   166  		return nh, proto, errors.Errorf("failed to parse next hop IP address %s", ipStr)
   167  	}
   168  	var au ip_types.AddressUnion
   169  	if ipv4 := netIP.To4(); ipv4 == nil {
   170  		var address ip_types.IP6Address
   171  		proto = fib_types.FIB_API_PATH_NH_PROTO_IP6
   172  		copy(address[:], netIP[:])
   173  		au.SetIP6(address)
   174  	} else {
   175  		var address ip_types.IP4Address
   176  		proto = fib_types.FIB_API_PATH_NH_PROTO_IP4
   177  		copy(address[:], netIP[12:])
   178  		au.SetIP4(address)
   179  	}
   180  	return fib_types.FibPathNh{
   181  		Address:            au,
   182  		ViaLabel:           NextHopViaLabelUnset,
   183  		ClassifyTableIndex: ClassifyTableIndexUnset,
   184  	}, proto, nil
   185  }