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

     1  //  Copyright (c) 2022 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 vpp2210
    16  
    17  import (
    18  	"fmt"
    19  	"net"
    20  
    21  	"github.com/pkg/errors"
    22  
    23  	"go.ligato.io/vpp-agent/v3/plugins/vpp"
    24  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2210/gtpu"
    25  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2210/interface_types"
    26  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2210/ip_types"
    27  	"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/vppcalls"
    28  	interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces"
    29  )
    30  
    31  const defaultDecapNextIndex = 0xFFFFFFFF
    32  
    33  func (h *InterfaceVppHandler) gtpuAddDelTunnel(isAdd bool, gtpuLink *interfaces.GtpuLink, multicastIf uint32) (uint32, error) {
    34  	var decapNextNode uint32 = defaultDecapNextIndex
    35  	if gtpuLink.DecapNextNode != 0 {
    36  		decapNextNode = gtpuLink.DecapNextNode
    37  	} else {
    38  		// backwards compatible fallback
    39  		if gtpuLink.DecapNext != interfaces.GtpuLink_DEFAULT {
    40  			decapNextNode = uint32(gtpuLink.DecapNext)
    41  		}
    42  	}
    43  
    44  	req := &gtpu.GtpuAddDelTunnel{
    45  		IsAdd:          isAdd,
    46  		McastSwIfIndex: interface_types.InterfaceIndex(multicastIf),
    47  		EncapVrfID:     gtpuLink.EncapVrfId,
    48  		Teid:           gtpuLink.Teid,
    49  		Tteid:          gtpuLink.RemoteTeid,
    50  		DecapNextIndex: decapNextNode,
    51  	}
    52  
    53  	srcAddr := net.ParseIP(gtpuLink.SrcAddr)
    54  	if srcAddr == nil {
    55  		err := errors.New("bad source address for GTPU tunnel")
    56  		return 0, err
    57  	}
    58  
    59  	dstAddr := net.ParseIP(gtpuLink.DstAddr)
    60  	if dstAddr == nil {
    61  		err := errors.New("bad destination address for GTPU tunnel")
    62  		return 0, err
    63  	}
    64  
    65  	if gtpuLink.SrcAddr == gtpuLink.DstAddr {
    66  		err := errors.New("source and destination are the same")
    67  		return 0, err
    68  	}
    69  
    70  	var isSrcIPv6, isDstIPv6 bool
    71  
    72  	if srcAddr.To4() == nil {
    73  		isSrcIPv6 = true
    74  	}
    75  	if dstAddr.To4() == nil {
    76  		isDstIPv6 = true
    77  	}
    78  
    79  	if !isSrcIPv6 && !isDstIPv6 {
    80  		var src, dst [4]uint8
    81  		copy(src[:], srcAddr.To4())
    82  		copy(dst[:], dstAddr.To4())
    83  		req.SrcAddress = ip_types.Address{
    84  			Af: ip_types.ADDRESS_IP4,
    85  			Un: ip_types.AddressUnionIP4(src),
    86  		}
    87  		req.DstAddress = ip_types.Address{
    88  			Af: ip_types.ADDRESS_IP4,
    89  			Un: ip_types.AddressUnionIP4(dst),
    90  		}
    91  	} else if isSrcIPv6 && isDstIPv6 {
    92  		var src, dst [16]uint8
    93  		copy(src[:], srcAddr.To16())
    94  		copy(dst[:], dstAddr.To16())
    95  		req.SrcAddress = ip_types.Address{
    96  			Af: ip_types.ADDRESS_IP6,
    97  			Un: ip_types.AddressUnionIP6(src),
    98  		}
    99  		req.DstAddress = ip_types.Address{
   100  			Af: ip_types.ADDRESS_IP6,
   101  			Un: ip_types.AddressUnionIP6(dst),
   102  		}
   103  	} else {
   104  		return 0, errors.New("source and destination addresses must be both either IPv4 or IPv6")
   105  	}
   106  
   107  	reply := &gtpu.GtpuAddDelTunnelReply{}
   108  
   109  	if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
   110  		return 0, err
   111  	}
   112  	return uint32(reply.SwIfIndex), nil
   113  }
   114  
   115  // AddGtpuTunnel adds new GTPU interface.
   116  func (h *InterfaceVppHandler) AddGtpuTunnel(ifName string, gtpuLink *interfaces.GtpuLink, multicastIf uint32) (uint32, error) {
   117  	if h.gtpu == nil {
   118  		return 0, errors.WithMessage(vpp.ErrPluginDisabled, "gtpu")
   119  	}
   120  	if gtpuLink == nil {
   121  		return 0, errors.New("missing GTPU tunnel information")
   122  	}
   123  
   124  	swIfIndex, err := h.gtpuAddDelTunnel(true, gtpuLink, multicastIf)
   125  	if err != nil {
   126  		return 0, err
   127  	}
   128  	return swIfIndex, h.SetInterfaceTag(ifName, swIfIndex)
   129  }
   130  
   131  // DelGtpuTunnel removes GTPU interface.
   132  func (h *InterfaceVppHandler) DelGtpuTunnel(ifName string, gtpuLink *interfaces.GtpuLink) error {
   133  	if h.gtpu == nil {
   134  		return errors.WithMessage(vpp.ErrPluginDisabled, "gtpu")
   135  	}
   136  	if gtpuLink == nil {
   137  		return errors.New("missing GTPU tunnel information")
   138  	}
   139  
   140  	swIfIndex, err := h.gtpuAddDelTunnel(false, gtpuLink, 0)
   141  	if err != nil {
   142  		return err
   143  	}
   144  	return h.RemoveInterfaceTag(ifName, swIfIndex)
   145  }
   146  
   147  // dumpGtpuDetails dumps GTP-U interface details from VPP and fills them into the provided interface map.
   148  func (h *InterfaceVppHandler) dumpGtpuDetails(ifc map[uint32]*vppcalls.InterfaceDetails) error {
   149  	if h.gtpu == nil {
   150  		// no-op when disabled
   151  		return nil
   152  	}
   153  
   154  	reqCtx := h.callsChannel.SendMultiRequest(&gtpu.GtpuTunnelDump{
   155  		SwIfIndex: ^interface_types.InterfaceIndex(0),
   156  	})
   157  	for {
   158  		gtpuDetails := &gtpu.GtpuTunnelDetails{}
   159  		stop, err := reqCtx.ReceiveReply(gtpuDetails)
   160  		if stop {
   161  			break // Break from the loop.
   162  		}
   163  		if err != nil {
   164  			return fmt.Errorf("failed to dump GTP-U tunnel interface details: %v", err)
   165  		}
   166  		_, ifIdxExists := ifc[uint32(gtpuDetails.SwIfIndex)]
   167  		if !ifIdxExists {
   168  			continue
   169  		}
   170  		// Multicast interface
   171  		var multicastIfName string
   172  		_, exists := ifc[uint32(gtpuDetails.McastSwIfIndex)]
   173  		if exists {
   174  			multicastIfName = ifc[uint32(gtpuDetails.McastSwIfIndex)].Interface.Name
   175  		}
   176  
   177  		gtpuLink := &interfaces.GtpuLink{
   178  			Multicast:     multicastIfName,
   179  			EncapVrfId:    gtpuDetails.EncapVrfID,
   180  			Teid:          gtpuDetails.Teid,
   181  			RemoteTeid:    gtpuDetails.Tteid,
   182  			DecapNextNode: gtpuDetails.DecapNextIndex,
   183  		}
   184  
   185  		if gtpuDetails.SrcAddress.Af == ip_types.ADDRESS_IP6 {
   186  			srcAddrArr := gtpuDetails.SrcAddress.Un.GetIP6()
   187  			gtpuLink.SrcAddr = net.IP(srcAddrArr[:]).To16().String()
   188  			dstAddrArr := gtpuDetails.DstAddress.Un.GetIP6()
   189  			gtpuLink.DstAddr = net.IP(dstAddrArr[:]).To16().String()
   190  		} else {
   191  			srcAddrArr := gtpuDetails.SrcAddress.Un.GetIP4()
   192  			gtpuLink.SrcAddr = net.IP(srcAddrArr[:4]).To4().String()
   193  			dstAddrArr := gtpuDetails.DstAddress.Un.GetIP4()
   194  			gtpuLink.DstAddr = net.IP(dstAddrArr[:4]).To4().String()
   195  		}
   196  
   197  		ifc[uint32(gtpuDetails.SwIfIndex)].Interface.Link = &interfaces.Interface_Gtpu{Gtpu: gtpuLink}
   198  		ifc[uint32(gtpuDetails.SwIfIndex)].Interface.Type = interfaces.Interface_GTPU_TUNNEL
   199  	}
   200  
   201  	return nil
   202  }