go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/ifplugin/vppcalls/vpp2101/dump_interface_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  	"bytes"
    19  	"context"
    20  	"encoding/hex"
    21  	"fmt"
    22  	"net"
    23  	"strings"
    24  
    25  	vpp_bond "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/bond"
    26  	vpp_dhcp "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/dhcp"
    27  	vpp_gre "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/gre"
    28  	vpp_ifs "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/interface"
    29  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/interface_types"
    30  	vpp_ip "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/ip"
    31  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/ip_types"
    32  	vpp_ipsec "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/ipsec"
    33  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/ipsec_types"
    34  	vpp_memif "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/memif"
    35  	vpp_tapv2 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/tapv2"
    36  	vpp_vxlan "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/vxlan"
    37  	vpp_vxlangpe "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/vxlan_gpe"
    38  	"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/vppcalls"
    39  	ifs "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces"
    40  	ipsec "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/ipsec"
    41  )
    42  
    43  const (
    44  	// allInterfaces defines unspecified interface index
    45  	allInterfaces = ^uint32(0)
    46  
    47  	// prefix prepended to internal names of untagged interfaces to construct unique
    48  	// logical names
    49  	untaggedIfPreffix = "UNTAGGED-"
    50  )
    51  
    52  const (
    53  	// Default VPP MTU value
    54  	defaultVPPMtu = 9216
    55  
    56  	// MAC length
    57  	macLength = 6
    58  )
    59  
    60  func getMtu(vppMtu uint16) uint32 {
    61  	// If default VPP MTU value is set, return 0 (it means MTU was not set in the NB config)
    62  	if vppMtu == defaultVPPMtu {
    63  		return 0
    64  	}
    65  	return uint32(vppMtu)
    66  }
    67  
    68  func (h *InterfaceVppHandler) DumpInterfacesByType(ctx context.Context, reqType ifs.Interface_Type) (map[uint32]*vppcalls.InterfaceDetails, error) {
    69  	// Dump all
    70  	ifs, err := h.DumpInterfaces(ctx)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	// Filter by type
    75  	for ifIdx, ifData := range ifs {
    76  		if ifData.Interface.Type != reqType {
    77  			delete(ifs, ifIdx)
    78  		}
    79  	}
    80  
    81  	return ifs, nil
    82  }
    83  
    84  func (h *InterfaceVppHandler) dumpInterfaces(ifIdxs ...uint32) (map[uint32]*vppcalls.InterfaceDetails, error) {
    85  	// map for the resulting interfaces
    86  	interfaces := make(map[uint32]*vppcalls.InterfaceDetails)
    87  
    88  	ifIdx := allInterfaces
    89  	if len(ifIdxs) > 0 {
    90  		ifIdx = ifIdxs[0]
    91  	}
    92  	// First, dump all interfaces to create initial data.
    93  	reqCtx := h.callsChannel.SendMultiRequest(&vpp_ifs.SwInterfaceDump{
    94  		SwIfIndex: interface_types.InterfaceIndex(ifIdx),
    95  	})
    96  	for {
    97  		ifDetails := &vpp_ifs.SwInterfaceDetails{}
    98  		stop, err := reqCtx.ReceiveReply(ifDetails)
    99  		if stop {
   100  			break
   101  		}
   102  		if err != nil {
   103  			return nil, fmt.Errorf("failed to dump interface: %v", err)
   104  		}
   105  
   106  		internalName := strings.TrimRight(ifDetails.InterfaceName, "\x00")
   107  		ifaceDevType := strings.TrimRight(ifDetails.InterfaceDevType, "\x00")
   108  		physAddr := make(net.HardwareAddr, macLength)
   109  		copy(physAddr, ifDetails.L2Address[:])
   110  
   111  		details := &vppcalls.InterfaceDetails{
   112  			Interface: &ifs.Interface{
   113  				Name: strings.TrimRight(ifDetails.Tag, "\x00"),
   114  				// the type may be amended later by further dumps
   115  				Type:        guessInterfaceType(ifaceDevType, internalName),
   116  				Enabled:     isAdminStateUp(ifDetails.Flags),
   117  				PhysAddress: net.HardwareAddr(ifDetails.L2Address[:]).String(),
   118  				Mtu:         getMtu(ifDetails.LinkMtu),
   119  			},
   120  			Meta: &vppcalls.InterfaceMeta{
   121  				SwIfIndex:      uint32(ifDetails.SwIfIndex),
   122  				SupSwIfIndex:   ifDetails.SupSwIfIndex,
   123  				L2Address:      physAddr,
   124  				InternalName:   internalName,
   125  				DevType:        ifaceDevType,
   126  				IsAdminStateUp: isAdminStateUp(ifDetails.Flags),
   127  				IsLinkStateUp:  isLinkStateUp(ifDetails.Flags),
   128  				LinkDuplex:     uint32(ifDetails.LinkDuplex),
   129  				LinkMTU:        ifDetails.LinkMtu,
   130  				MTU:            ifDetails.Mtu,
   131  				LinkSpeed:      ifDetails.LinkSpeed,
   132  				SubID:          ifDetails.SubID,
   133  				Tag:            strings.TrimRight(ifDetails.Tag, "\x00"),
   134  			},
   135  		}
   136  
   137  		// sub interface
   138  		if ifDetails.SupSwIfIndex != uint32(ifDetails.SwIfIndex) {
   139  			details.Interface.Type = ifs.Interface_SUB_INTERFACE
   140  			details.Interface.Link = &ifs.Interface_Sub{
   141  				Sub: &ifs.SubInterface{
   142  					ParentName:  interfaces[ifDetails.SupSwIfIndex].Interface.Name,
   143  					SubId:       ifDetails.SubID,
   144  					TagRwOption: getTagRwOption(ifDetails.VtrOp),
   145  					PushDot1Q:   uintToBool(uint8(ifDetails.VtrPushDot1q)),
   146  					Tag1:        ifDetails.VtrTag1,
   147  					Tag2:        ifDetails.VtrTag2,
   148  				},
   149  			}
   150  		}
   151  		// Fill name for physical interfaces (they are mostly without tag)
   152  		switch details.Interface.Type {
   153  		case ifs.Interface_DPDK:
   154  			details.Interface.Name = internalName
   155  		case ifs.Interface_AF_PACKET:
   156  			details.Interface.Link = &ifs.Interface_Afpacket{
   157  				Afpacket: &ifs.AfpacketLink{
   158  					HostIfName: strings.TrimPrefix(internalName, "host-"),
   159  				},
   160  			}
   161  		}
   162  		if details.Interface.Name == "" {
   163  			// untagged interface - generate a logical name for it
   164  			// (apart from local0 it will get removed by resync)
   165  			details.Interface.Name = untaggedIfPreffix + internalName
   166  		}
   167  		interfaces[uint32(ifDetails.SwIfIndex)] = details
   168  	}
   169  
   170  	return interfaces, nil
   171  }
   172  
   173  func (h *InterfaceVppHandler) DumpInterfaces(ctx context.Context) (map[uint32]*vppcalls.InterfaceDetails, error) {
   174  	// Dump all interfaces
   175  	interfaces, err := h.dumpInterfaces()
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  
   180  	// Get DHCP clients
   181  	dhcpClients, err := h.DumpDhcpClients()
   182  	if err != nil {
   183  		return nil, fmt.Errorf("failed to dump interface DHCP clients: %v", err)
   184  	}
   185  
   186  	// Get IP addresses before VRF
   187  	err = h.dumpIPAddressDetails(interfaces, false, dhcpClients)
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  	err = h.dumpIPAddressDetails(interfaces, true, dhcpClients)
   192  	if err != nil {
   193  		return nil, err
   194  	}
   195  
   196  	// Get unnumbered interfaces
   197  	unnumbered, err := h.dumpUnnumberedDetails()
   198  	if err != nil {
   199  		return nil, fmt.Errorf("failed to dump unnumbered interfaces: %v", err)
   200  	}
   201  
   202  	// dump VXLAN details before VRFs (used by isIpv6Interface)
   203  	err = h.dumpVxlanDetails(interfaces)
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  
   208  	err = h.dumpVxLanGpeDetails(interfaces)
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  
   213  	// Get interface VRF for every IP family, fill DHCP if set and resolve unnumbered interface setup
   214  	for _, ifData := range interfaces {
   215  		// VRF is stored in metadata for both, IPv4 and IPv6. If the interface is an IPv6 interface (it contains at least
   216  		// one IPv6 address), appropriate VRF is stored also in modelled data
   217  		ipv4Vrf, err := h.GetInterfaceVrf(ifData.Meta.SwIfIndex)
   218  		if err != nil {
   219  			return nil, fmt.Errorf("interface dump: failed to get IPv4 VRF from interface %d: %v",
   220  				ifData.Meta.SwIfIndex, err)
   221  		}
   222  		ifData.Meta.VrfIPv4 = ipv4Vrf
   223  		ipv6Vrf, err := h.GetInterfaceVrfIPv6(ifData.Meta.SwIfIndex)
   224  		if err != nil {
   225  			return nil, fmt.Errorf("interface dump: failed to get IPv6 VRF from interface %d: %v",
   226  				ifData.Meta.SwIfIndex, err)
   227  		}
   228  		ifData.Meta.VrfIPv6 = ipv6Vrf
   229  		if isIPv6If, err := isIpv6Interface(ifData.Interface); err != nil {
   230  			return interfaces, err
   231  		} else if isIPv6If {
   232  			ifData.Interface.Vrf = ipv6Vrf
   233  		} else {
   234  			ifData.Interface.Vrf = ipv4Vrf
   235  		}
   236  
   237  		// DHCP
   238  		dhcpData, ok := dhcpClients[ifData.Meta.SwIfIndex]
   239  		if ok {
   240  			ifData.Interface.SetDhcpClient = true
   241  			ifData.Meta.Dhcp = dhcpData
   242  		}
   243  		// Unnumbered
   244  		ifWithIPIdx, ok := unnumbered[ifData.Meta.SwIfIndex]
   245  		if ok {
   246  			// Find unnumbered interface
   247  			var ifWithIPName string
   248  			ifWithIP, ok := interfaces[ifWithIPIdx]
   249  			if ok {
   250  				ifWithIPName = ifWithIP.Interface.Name
   251  			} else {
   252  				h.log.Debugf("cannot find name of the ip-interface for unnumbered %s", ifData.Interface.Name)
   253  				ifWithIPName = "<unknown>"
   254  			}
   255  			ifData.Interface.Unnumbered = &ifs.Interface_Unnumbered{
   256  				InterfaceWithIp: ifWithIPName,
   257  			}
   258  		}
   259  	}
   260  
   261  	err = h.dumpMemifDetails(ctx, interfaces)
   262  	if err != nil {
   263  		return nil, err
   264  	}
   265  
   266  	err = h.dumpTapDetails(interfaces)
   267  	if err != nil {
   268  		return nil, err
   269  	}
   270  
   271  	err = h.dumpIPSecTunnelDetails(interfaces)
   272  	if err != nil {
   273  		return nil, err
   274  	}
   275  
   276  	err = h.dumpVmxNet3Details(interfaces)
   277  	if err != nil {
   278  		return nil, err
   279  	}
   280  
   281  	err = h.dumpBondDetails(interfaces)
   282  	if err != nil {
   283  		return nil, err
   284  	}
   285  
   286  	err = h.dumpGreDetails(interfaces)
   287  	if err != nil {
   288  		return nil, err
   289  	}
   290  
   291  	err = h.dumpGtpuDetails(interfaces)
   292  	if err != nil {
   293  		return nil, err
   294  	}
   295  
   296  	err = h.dumpIpipDetails(interfaces)
   297  	if err != nil {
   298  		return nil, err
   299  	}
   300  
   301  	err = h.dumpWireguardDetails(interfaces)
   302  	if err != nil {
   303  		return nil, err
   304  	}
   305  
   306  	// Rx-placement dump is last since it uses interface type-specific data
   307  	err = h.dumpRxPlacement(interfaces)
   308  	if err != nil {
   309  		return nil, err
   310  	}
   311  
   312  	return interfaces, nil
   313  }
   314  
   315  // DumpDhcpClients returns a slice of DhcpMeta with all interfaces and other DHCP-related information available
   316  func (h *InterfaceVppHandler) DumpDhcpClients() (map[uint32]*vppcalls.Dhcp, error) {
   317  	dhcpData := make(map[uint32]*vppcalls.Dhcp)
   318  	reqCtx := h.callsChannel.SendMultiRequest(&vpp_dhcp.DHCPClientDump{})
   319  
   320  	for {
   321  		dhcpDetails := &vpp_dhcp.DHCPClientDetails{}
   322  		last, err := reqCtx.ReceiveReply(dhcpDetails)
   323  		if last {
   324  			break
   325  		}
   326  		if err != nil {
   327  			return nil, err
   328  		}
   329  		client := dhcpDetails.Client
   330  		lease := dhcpDetails.Lease
   331  
   332  		// DHCP client data
   333  		dhcpClient := &vppcalls.Client{
   334  			SwIfIndex:        uint32(client.SwIfIndex),
   335  			Hostname:         strings.TrimRight(client.Hostname, "\x00"),
   336  			ID:               string(bytes.SplitN(client.ID, []byte{0x00}, 2)[0]),
   337  			WantDhcpEvent:    client.WantDHCPEvent,
   338  			SetBroadcastFlag: client.SetBroadcastFlag,
   339  			PID:              client.PID,
   340  		}
   341  
   342  		// DHCP lease data
   343  		dhcpLease := &vppcalls.Lease{
   344  			SwIfIndex:     uint32(lease.SwIfIndex),
   345  			State:         uint8(lease.State),
   346  			Hostname:      strings.TrimRight(lease.Hostname, "\x00"),
   347  			IsIPv6:        lease.IsIPv6,
   348  			HostAddress:   dhcpAddressToString(lease.HostAddress, uint32(lease.MaskWidth), lease.IsIPv6),
   349  			RouterAddress: dhcpAddressToString(lease.RouterAddress, uint32(lease.MaskWidth), lease.IsIPv6),
   350  			HostMac:       net.HardwareAddr(lease.HostMac[:]).String(),
   351  		}
   352  
   353  		// DHCP metadata
   354  		dhcpData[uint32(client.SwIfIndex)] = &vppcalls.Dhcp{
   355  			Client: dhcpClient,
   356  			Lease:  dhcpLease,
   357  		}
   358  	}
   359  
   360  	return dhcpData, nil
   361  }
   362  
   363  // DumpInterfaceStates dumps link and administrative state of every interface.
   364  func (h *InterfaceVppHandler) DumpInterfaceStates(ifIdxs ...uint32) (map[uint32]*vppcalls.InterfaceState, error) {
   365  	// Dump all interface states if not specified.
   366  	if len(ifIdxs) == 0 {
   367  		ifIdxs = []uint32{allInterfaces}
   368  	}
   369  
   370  	ifStates := make(map[uint32]*vppcalls.InterfaceState)
   371  	for _, ifIdx := range ifIdxs {
   372  		reqCtx := h.callsChannel.SendMultiRequest(&vpp_ifs.SwInterfaceDump{
   373  			SwIfIndex: interface_types.InterfaceIndex(ifIdx),
   374  		})
   375  		for {
   376  			ifDetails := &vpp_ifs.SwInterfaceDetails{}
   377  			stop, err := reqCtx.ReceiveReply(ifDetails)
   378  			if stop {
   379  				break // Break from the loop.
   380  			}
   381  			if err != nil {
   382  				return nil, fmt.Errorf("failed to dump interface states: %v", err)
   383  			}
   384  
   385  			physAddr := make(net.HardwareAddr, macLength)
   386  			copy(physAddr, ifDetails.L2Address[:])
   387  
   388  			ifaceState := vppcalls.InterfaceState{
   389  				SwIfIndex:    uint32(ifDetails.SwIfIndex),
   390  				InternalName: strings.TrimRight(ifDetails.InterfaceName, "\x00"),
   391  				PhysAddress:  physAddr,
   392  				AdminState:   adminStateToInterfaceStatus(ifDetails.Flags),
   393  				LinkState:    linkStateToInterfaceStatus(ifDetails.Flags),
   394  				LinkDuplex:   toLinkDuplex(ifDetails.LinkDuplex),
   395  				LinkSpeed:    toLinkSpeed(ifDetails.LinkSpeed),
   396  				LinkMTU:      ifDetails.LinkMtu,
   397  			}
   398  			ifStates[uint32(ifDetails.SwIfIndex)] = &ifaceState
   399  		}
   400  	}
   401  
   402  	return ifStates, nil
   403  }
   404  
   405  func toLinkDuplex(duplex interface_types.LinkDuplex) ifs.InterfaceState_Duplex {
   406  	switch duplex {
   407  	case 1:
   408  		return ifs.InterfaceState_HALF
   409  	case 2:
   410  		return ifs.InterfaceState_FULL
   411  	default:
   412  		return ifs.InterfaceState_UNKNOWN_DUPLEX
   413  	}
   414  }
   415  
   416  const megabit = 1000000 // one megabit in bytes
   417  
   418  func toLinkSpeed(speed uint32) uint64 {
   419  	switch speed {
   420  	case 1:
   421  		return 10 * megabit // 10M
   422  	case 2:
   423  		return 100 * megabit // 100M
   424  	case 4:
   425  		return 1000 * megabit // 1G
   426  	case 8:
   427  		return 10000 * megabit // 10G
   428  	case 16:
   429  		return 40000 * megabit // 40G
   430  	case 32:
   431  		return 100000 * megabit // 100G
   432  	default:
   433  		return 0
   434  	}
   435  }
   436  
   437  // Returns true if given interface contains at least one IPv6 address. For VxLAN, source and destination
   438  // addresses are also checked
   439  func isIpv6Interface(iface *ifs.Interface) (bool, error) {
   440  	if iface.Type == ifs.Interface_VXLAN_TUNNEL && iface.GetVxlan() != nil {
   441  		if ipAddress := net.ParseIP(iface.GetVxlan().SrcAddress); ipAddress.To4() == nil {
   442  			return true, nil
   443  		}
   444  		if ipAddress := net.ParseIP(iface.GetVxlan().DstAddress); ipAddress.To4() == nil {
   445  			return true, nil
   446  		}
   447  	}
   448  	for _, ifAddress := range iface.IpAddresses {
   449  		if ipAddress, _, err := net.ParseCIDR(ifAddress); err != nil {
   450  			return false, err
   451  		} else if ipAddress.To4() == nil {
   452  			return true, nil
   453  		}
   454  	}
   455  	return false, nil
   456  }
   457  
   458  // dumpIPAddressDetails dumps IP address details of interfaces from VPP and fills them into the provided interface map.
   459  func (h *InterfaceVppHandler) dumpIPAddressDetails(ifs map[uint32]*vppcalls.InterfaceDetails, isIPv6 bool, dhcpClients map[uint32]*vppcalls.Dhcp) error {
   460  	// Dump IP addresses of each interface.
   461  	for idx := range ifs {
   462  		reqCtx := h.callsChannel.SendMultiRequest(&vpp_ip.IPAddressDump{
   463  			SwIfIndex: interface_types.InterfaceIndex(idx),
   464  			IsIPv6:    isIPv6,
   465  		})
   466  		for {
   467  			ipDetails := &vpp_ip.IPAddressDetails{}
   468  			stop, err := reqCtx.ReceiveReply(ipDetails)
   469  			if stop {
   470  				break // Break from the loop.
   471  			}
   472  			if err != nil {
   473  				return fmt.Errorf("failed to dump interface %d IP address details: %v", idx, err)
   474  			}
   475  			h.processIPDetails(ifs, ipDetails, dhcpClients)
   476  		}
   477  	}
   478  
   479  	return nil
   480  }
   481  
   482  // processIPDetails processes ip.IPAddressDetails binary API message and fills the details into the provided interface map.
   483  func (h *InterfaceVppHandler) processIPDetails(ifs map[uint32]*vppcalls.InterfaceDetails, ipDetails *vpp_ip.IPAddressDetails, dhcpClients map[uint32]*vppcalls.Dhcp) {
   484  	ifDetails, ifIdxExists := ifs[uint32(ipDetails.SwIfIndex)]
   485  	if !ifIdxExists {
   486  		return
   487  	}
   488  
   489  	var ipAddr string
   490  	ipByte := make([]byte, 16)
   491  	copy(ipByte[:], ipDetails.Prefix.Address.Un.XXX_UnionData[:])
   492  	if ipDetails.Prefix.Address.Af == ip_types.ADDRESS_IP6 {
   493  		ipAddr = fmt.Sprintf("%s/%d", net.IP(ipByte).To16().String(), uint32(ipDetails.Prefix.Len))
   494  	} else {
   495  		ipAddr = fmt.Sprintf("%s/%d", net.IP(ipByte[:4]).To4().String(), uint32(ipDetails.Prefix.Len))
   496  	}
   497  
   498  	// skip IP addresses given by DHCP
   499  	if dhcpClient, hasDhcpClient := dhcpClients[uint32(ipDetails.SwIfIndex)]; hasDhcpClient {
   500  		if dhcpClient.Lease != nil && dhcpClient.Lease.HostAddress == ipAddr {
   501  			return
   502  		}
   503  	}
   504  
   505  	ifDetails.Interface.IpAddresses = append(ifDetails.Interface.IpAddresses, ipAddr)
   506  }
   507  
   508  // dumpTapDetails dumps tap interface details from VPP and fills them into the provided interface map.
   509  func (h *InterfaceVppHandler) dumpTapDetails(interfaces map[uint32]*vppcalls.InterfaceDetails) error {
   510  	// Original TAP v1 was DEPRECATED
   511  
   512  	// TAP v2
   513  	reqCtx := h.callsChannel.SendMultiRequest(&vpp_tapv2.SwInterfaceTapV2Dump{
   514  		SwIfIndex: ^interface_types.InterfaceIndex(0),
   515  	})
   516  	for {
   517  		tapDetails := &vpp_tapv2.SwInterfaceTapV2Details{}
   518  		stop, err := reqCtx.ReceiveReply(tapDetails)
   519  		if stop {
   520  			break // Break from the loop.
   521  		}
   522  		if err != nil {
   523  			return fmt.Errorf("failed to dump TAPv2 interface details: %v", err)
   524  		}
   525  		_, ifIdxExists := interfaces[tapDetails.SwIfIndex]
   526  		if !ifIdxExists {
   527  			continue
   528  		}
   529  		interfaces[tapDetails.SwIfIndex].Interface.Link = &ifs.Interface_Tap{
   530  			Tap: &ifs.TapLink{
   531  				Version:      2,
   532  				HostIfName:   cleanString(tapDetails.HostIfName),
   533  				RxRingSize:   uint32(tapDetails.RxRingSz),
   534  				TxRingSize:   uint32(tapDetails.TxRingSz),
   535  				EnableGso:    tapDetails.TapFlags&vpp_tapv2.TAP_API_FLAG_GSO == vpp_tapv2.TAP_API_FLAG_GSO,
   536  				EnableTunnel: tapDetails.TapFlags&vpp_tapv2.TAP_API_FLAG_TUN == vpp_tapv2.TAP_API_FLAG_TUN,
   537  			},
   538  		}
   539  		interfaces[tapDetails.SwIfIndex].Interface.Type = ifs.Interface_TAP
   540  	}
   541  
   542  	return nil
   543  }
   544  
   545  // dumpVxlanDetails dumps VXLAN interface details from VPP and fills them into the provided interface map.
   546  func (h *InterfaceVppHandler) dumpVxlanDetails(interfaces map[uint32]*vppcalls.InterfaceDetails) error {
   547  	reqCtx := h.callsChannel.SendMultiRequest(&vpp_vxlan.VxlanTunnelDump{
   548  		SwIfIndex: ^interface_types.InterfaceIndex(0),
   549  	})
   550  	for {
   551  		vxlanDetails := &vpp_vxlan.VxlanTunnelDetails{}
   552  		stop, err := reqCtx.ReceiveReply(vxlanDetails)
   553  		if stop {
   554  			break // Break from the loop.
   555  		}
   556  		if err != nil {
   557  			return fmt.Errorf("failed to dump VxLAN tunnel interface details: %v", err)
   558  		}
   559  		_, ifIdxExists := interfaces[uint32(vxlanDetails.SwIfIndex)]
   560  		if !ifIdxExists {
   561  			continue
   562  		}
   563  		// Multicast interface
   564  		var multicastIfName string
   565  		_, exists := interfaces[uint32(vxlanDetails.McastSwIfIndex)]
   566  		if exists {
   567  			multicastIfName = interfaces[uint32(vxlanDetails.McastSwIfIndex)].Interface.Name
   568  		}
   569  
   570  		if vxlanDetails.SrcAddress.Af == ip_types.ADDRESS_IP6 {
   571  			srcIP := vxlanDetails.SrcAddress.Un.GetIP6()
   572  			dstIP := vxlanDetails.DstAddress.Un.GetIP6()
   573  			interfaces[uint32(vxlanDetails.SwIfIndex)].Interface.Link = &ifs.Interface_Vxlan{
   574  				Vxlan: &ifs.VxlanLink{
   575  					Multicast:  multicastIfName,
   576  					SrcAddress: net.IP(srcIP[:]).To16().String(),
   577  					DstAddress: net.IP(dstIP[:]).To16().String(),
   578  					Vni:        vxlanDetails.Vni,
   579  				},
   580  			}
   581  		} else {
   582  			srcIP := vxlanDetails.SrcAddress.Un.GetIP4()
   583  			dstIP := vxlanDetails.DstAddress.Un.GetIP4()
   584  			interfaces[uint32(vxlanDetails.SwIfIndex)].Interface.Link = &ifs.Interface_Vxlan{
   585  				Vxlan: &ifs.VxlanLink{
   586  					Multicast:  multicastIfName,
   587  					SrcAddress: net.IP(srcIP[:4]).To4().String(),
   588  					DstAddress: net.IP(dstIP[:4]).To4().String(),
   589  					Vni:        vxlanDetails.Vni,
   590  				},
   591  			}
   592  		}
   593  		interfaces[uint32(vxlanDetails.SwIfIndex)].Interface.Type = ifs.Interface_VXLAN_TUNNEL
   594  	}
   595  
   596  	return nil
   597  }
   598  
   599  // dumpVxlanDetails dumps VXLAN-GPE interface details from VPP and fills them into the provided interface map.
   600  func (h *InterfaceVppHandler) dumpVxLanGpeDetails(interfaces map[uint32]*vppcalls.InterfaceDetails) error {
   601  	reqCtx := h.callsChannel.SendMultiRequest(&vpp_vxlangpe.VxlanGpeTunnelDump{SwIfIndex: ^interface_types.InterfaceIndex(0)})
   602  	for {
   603  		vxlanGpeDetails := &vpp_vxlangpe.VxlanGpeTunnelDetails{}
   604  		stop, err := reqCtx.ReceiveReply(vxlanGpeDetails)
   605  		if stop {
   606  			break // Break from the loop.
   607  		}
   608  		if err != nil {
   609  			return fmt.Errorf("failed to dump VxLAN-GPE tunnel interface details: %v", err)
   610  		}
   611  		_, ifIdxExists := interfaces[uint32(vxlanGpeDetails.SwIfIndex)]
   612  		if !ifIdxExists {
   613  			continue
   614  		}
   615  		// Multicast interface
   616  		var multicastIfName string
   617  		_, exists := interfaces[uint32(vxlanGpeDetails.McastSwIfIndex)]
   618  		if exists {
   619  			multicastIfName = interfaces[uint32(vxlanGpeDetails.McastSwIfIndex)].Interface.Name
   620  		}
   621  
   622  		vxLan := &ifs.VxlanLink{
   623  			Multicast: multicastIfName,
   624  			Vni:       vxlanGpeDetails.Vni,
   625  			Gpe: &ifs.VxlanLink_Gpe{
   626  				DecapVrfId: vxlanGpeDetails.DecapVrfID,
   627  				Protocol:   getVxLanGpeProtocol(vxlanGpeDetails.Protocol),
   628  			},
   629  		}
   630  
   631  		if vxlanGpeDetails.IsIPv6 {
   632  			localIP := vxlanGpeDetails.Local.Un.GetIP6()
   633  			remoteIP := vxlanGpeDetails.Remote.Un.GetIP6()
   634  			vxLan.SrcAddress = net.IP(localIP[:]).To16().String()
   635  			vxLan.DstAddress = net.IP(remoteIP[:]).To16().String()
   636  		} else {
   637  			localIP := vxlanGpeDetails.Local.Un.GetIP4()
   638  			remoteIP := vxlanGpeDetails.Remote.Un.GetIP4()
   639  			vxLan.SrcAddress = net.IP(localIP[:4]).To4().String()
   640  			vxLan.DstAddress = net.IP(remoteIP[:4]).To4().String()
   641  		}
   642  
   643  		interfaces[uint32(vxlanGpeDetails.SwIfIndex)].Interface.Link = &ifs.Interface_Vxlan{Vxlan: vxLan}
   644  		interfaces[uint32(vxlanGpeDetails.SwIfIndex)].Interface.Type = ifs.Interface_VXLAN_TUNNEL
   645  	}
   646  
   647  	return nil
   648  }
   649  
   650  // dumpIPSecTunnelDetails dumps IPSec tunnel interfaces from the VPP and fills them into the provided interface map.
   651  func (h *InterfaceVppHandler) dumpIPSecTunnelDetails(interfaces map[uint32]*vppcalls.InterfaceDetails) error {
   652  	// tunnel interfaces are a part of security association dump
   653  	var tunnels []*vpp_ipsec.IpsecSaDetails
   654  	req := &vpp_ipsec.IpsecSaDump{
   655  		SaID: ^uint32(0),
   656  	}
   657  	requestCtx := h.callsChannel.SendMultiRequest(req)
   658  
   659  	for {
   660  		saDetails := &vpp_ipsec.IpsecSaDetails{}
   661  		stop, err := requestCtx.ReceiveReply(saDetails)
   662  		if stop {
   663  			break
   664  		}
   665  		if err != nil {
   666  			return err
   667  		}
   668  		// skip non-tunnel security associations
   669  		if saDetails.SwIfIndex != ^interface_types.InterfaceIndex(0) {
   670  			tunnels = append(tunnels, saDetails)
   671  		}
   672  	}
   673  
   674  	// every tunnel interface is returned in two API calls. To reconstruct the correct proto-modelled data,
   675  	// first appearance is cached, and when the second part arrives, data are completed and stored.
   676  	tunnelParts := make(map[uint32]*vpp_ipsec.IpsecSaDetails)
   677  
   678  	for _, tunnel := range tunnels {
   679  		// first appearance is stored in the map, the second one is used in configuration.
   680  		firstSaData, ok := tunnelParts[uint32(tunnel.SwIfIndex)]
   681  		if !ok {
   682  			tunnelParts[uint32(tunnel.SwIfIndex)] = tunnel
   683  			continue
   684  		}
   685  
   686  		local := firstSaData
   687  		remote := tunnel
   688  
   689  		// verify data for local & remote
   690  		if err := verifyIPSecTunnelDetails(local, remote); err != nil {
   691  			h.log.Warnf("IPSec SA dump for tunnel interface data does not match: %v", err)
   692  			continue
   693  		}
   694  
   695  		var localIP, remoteIP net.IP
   696  		if tunnel.Entry.TunnelDst.Af == ip_types.ADDRESS_IP6 {
   697  			localSrc := local.Entry.TunnelSrc.Un.GetIP6()
   698  			remoteSrc := remote.Entry.TunnelSrc.Un.GetIP6()
   699  			localIP, remoteIP = net.IP(localSrc[:]), net.IP(remoteSrc[:])
   700  		} else {
   701  			localSrc := local.Entry.TunnelSrc.Un.GetIP4()
   702  			remoteSrc := remote.Entry.TunnelSrc.Un.GetIP4()
   703  			localIP, remoteIP = net.IP(localSrc[:]), net.IP(remoteSrc[:])
   704  		}
   705  
   706  		ifDetails, ok := interfaces[uint32(tunnel.SwIfIndex)]
   707  		if !ok {
   708  			h.log.Warnf("ipsec SA dump returned unrecognized swIfIndex: %v", tunnel.SwIfIndex)
   709  			continue
   710  		}
   711  		ifDetails.Interface.Type = ifs.Interface_IPSEC_TUNNEL
   712  		ifDetails.Interface.Link = &ifs.Interface_Ipsec{
   713  			Ipsec: &ifs.IPSecLink{
   714  				Esn:             (tunnel.Entry.Flags & ipsec_types.IPSEC_API_SAD_FLAG_USE_ESN) != 0,
   715  				AntiReplay:      (tunnel.Entry.Flags & ipsec_types.IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY) != 0,
   716  				LocalIp:         localIP.String(),
   717  				RemoteIp:        remoteIP.String(),
   718  				LocalSpi:        local.Entry.Spi,
   719  				RemoteSpi:       remote.Entry.Spi,
   720  				CryptoAlg:       ipsec.CryptoAlg(tunnel.Entry.CryptoAlgorithm),
   721  				LocalCryptoKey:  hex.EncodeToString(local.Entry.CryptoKey.Data[:local.Entry.CryptoKey.Length]),
   722  				RemoteCryptoKey: hex.EncodeToString(remote.Entry.CryptoKey.Data[:remote.Entry.CryptoKey.Length]),
   723  				IntegAlg:        ipsec.IntegAlg(tunnel.Entry.IntegrityAlgorithm),
   724  				LocalIntegKey:   hex.EncodeToString(local.Entry.IntegrityKey.Data[:local.Entry.IntegrityKey.Length]),
   725  				RemoteIntegKey:  hex.EncodeToString(remote.Entry.IntegrityKey.Data[:remote.Entry.IntegrityKey.Length]),
   726  				EnableUdpEncap:  (tunnel.Entry.Flags & ipsec_types.IPSEC_API_SAD_FLAG_UDP_ENCAP) != 0,
   727  			},
   728  		}
   729  	}
   730  
   731  	return nil
   732  }
   733  
   734  func verifyIPSecTunnelDetails(local, remote *vpp_ipsec.IpsecSaDetails) error {
   735  	if local.SwIfIndex != remote.SwIfIndex {
   736  		return fmt.Errorf("swIfIndex data mismatch (local: %v, remote: %v)",
   737  			local.SwIfIndex, remote.SwIfIndex)
   738  	}
   739  	localIsTunnel := local.Entry.Flags & ipsec_types.IPSEC_API_SAD_FLAG_IS_TUNNEL
   740  	remoteIsTunnel := remote.Entry.Flags & ipsec_types.IPSEC_API_SAD_FLAG_IS_TUNNEL
   741  	if localIsTunnel != remoteIsTunnel {
   742  		return fmt.Errorf("tunnel data mismatch (local: %v, remote: %v)",
   743  			localIsTunnel, remoteIsTunnel)
   744  	}
   745  
   746  	localSrc, localDst := local.Entry.TunnelSrc.Un.XXX_UnionData, local.Entry.TunnelDst.Un.XXX_UnionData
   747  	remoteSrc, remoteDst := remote.Entry.TunnelSrc.Un.XXX_UnionData, remote.Entry.TunnelDst.Un.XXX_UnionData
   748  	if (local.Entry.Flags&ipsec_types.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6) != (remote.Entry.Flags&ipsec_types.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6) ||
   749  		!bytes.Equal(localSrc[:], remoteDst[:]) ||
   750  		!bytes.Equal(localDst[:], remoteSrc[:]) {
   751  		return fmt.Errorf("src/dst IP mismatch (local: %+v, remote: %+v)",
   752  			local.Entry, remote.Entry)
   753  	}
   754  
   755  	return nil
   756  }
   757  
   758  // dumpBondDetails dumps bond interface details from VPP and fills them into the provided interface map.
   759  func (h *InterfaceVppHandler) dumpBondDetails(interfaces map[uint32]*vppcalls.InterfaceDetails) error {
   760  	bondIndexes := make([]uint32, 0)
   761  	reqCtx := h.callsChannel.SendMultiRequest(&vpp_bond.SwInterfaceBondDump{})
   762  	for {
   763  		bondDetails := &vpp_bond.SwInterfaceBondDetails{}
   764  		stop, err := reqCtx.ReceiveReply(bondDetails)
   765  		if err != nil {
   766  			return fmt.Errorf("failed to dump bond interface details: %v", err)
   767  		}
   768  		if stop {
   769  			break
   770  		}
   771  		_, ifIdxExists := interfaces[uint32(bondDetails.SwIfIndex)]
   772  		if !ifIdxExists {
   773  			continue
   774  		}
   775  		interfaces[uint32(bondDetails.SwIfIndex)].Interface.Link = &ifs.Interface_Bond{
   776  			Bond: &ifs.BondLink{
   777  				Id:   bondDetails.ID,
   778  				Mode: getBondIfMode(bondDetails.Mode),
   779  				Lb:   getBondLoadBalance(bondDetails.Lb),
   780  			},
   781  		}
   782  		interfaces[uint32(bondDetails.SwIfIndex)].Interface.Type = ifs.Interface_BOND_INTERFACE
   783  		bondIndexes = append(bondIndexes, uint32(bondDetails.SwIfIndex))
   784  	}
   785  
   786  	// get slave interfaces for bonds
   787  	for _, bondIdx := range bondIndexes {
   788  		var bondSlaves []*ifs.BondLink_BondedInterface
   789  		reqSlCtx := h.callsChannel.SendMultiRequest(&vpp_bond.SwInterfaceSlaveDump{
   790  			SwIfIndex: interface_types.InterfaceIndex(bondIdx),
   791  		})
   792  		for {
   793  			slaveDetails := &vpp_bond.SwInterfaceSlaveDetails{}
   794  			stop, err := reqSlCtx.ReceiveReply(slaveDetails)
   795  			if err != nil {
   796  				return fmt.Errorf("failed to dump bond slave details: %v", err)
   797  			}
   798  			if stop {
   799  				break
   800  			}
   801  			slaveIf, ifIdxExists := interfaces[uint32(slaveDetails.SwIfIndex)]
   802  			if !ifIdxExists {
   803  				continue
   804  			}
   805  			bondSlaves = append(bondSlaves, &ifs.BondLink_BondedInterface{
   806  				Name:          slaveIf.Interface.Name,
   807  				IsPassive:     slaveDetails.IsPassive,
   808  				IsLongTimeout: slaveDetails.IsLongTimeout,
   809  			})
   810  			interfaces[bondIdx].Interface.GetBond().BondedInterfaces = bondSlaves
   811  		}
   812  	}
   813  
   814  	return nil
   815  }
   816  
   817  func (h *InterfaceVppHandler) dumpGreDetails(interfaces map[uint32]*vppcalls.InterfaceDetails) error {
   818  	msg := &vpp_gre.GreTunnelDump{SwIfIndex: interface_types.InterfaceIndex(^uint32(0))}
   819  	reqCtx := h.callsChannel.SendMultiRequest(msg)
   820  	for {
   821  		greDetails := &vpp_gre.GreTunnelDetails{}
   822  		stop, err := reqCtx.ReceiveReply(greDetails)
   823  		if stop {
   824  			break
   825  		}
   826  		if err != nil {
   827  			return fmt.Errorf("failed to dump span: %v", err)
   828  		}
   829  
   830  		tunnel := greDetails.Tunnel
   831  		swIfIndex := uint32(tunnel.SwIfIndex)
   832  
   833  		var srcAddr, dstAddr net.IP
   834  		if tunnel.Src.Af == ip_types.ADDRESS_IP4 {
   835  			srcAddrArr := tunnel.Src.Un.GetIP4()
   836  			srcAddr = net.IP(srcAddrArr[:])
   837  		} else {
   838  			srcAddrArr := tunnel.Src.Un.GetIP6()
   839  			srcAddr = net.IP(srcAddrArr[:])
   840  		}
   841  		if tunnel.Dst.Af == ip_types.ADDRESS_IP4 {
   842  			dstAddrArr := tunnel.Dst.Un.GetIP4()
   843  			dstAddr = net.IP(dstAddrArr[:])
   844  		} else {
   845  			dstAddrArr := tunnel.Dst.Un.GetIP6()
   846  			dstAddr = net.IP(dstAddrArr[:])
   847  		}
   848  
   849  		interfaces[swIfIndex].Interface.Link = &ifs.Interface_Gre{
   850  			Gre: &ifs.GreLink{
   851  				TunnelType: getGreTunnelType(tunnel.Type),
   852  				SrcAddr:    srcAddr.String(),
   853  				DstAddr:    dstAddr.String(),
   854  				OuterFibId: tunnel.OuterTableID,
   855  				SessionId:  uint32(tunnel.SessionID),
   856  			},
   857  		}
   858  		interfaces[swIfIndex].Interface.Type = ifs.Interface_GRE_TUNNEL
   859  	}
   860  	return nil
   861  }
   862  
   863  // dumpUnnumberedDetails returns a map of unnumbered interface indexes, every with interface index of element with IP
   864  func (h *InterfaceVppHandler) dumpUnnumberedDetails() (map[uint32]uint32, error) {
   865  	unIfMap := make(map[uint32]uint32) // unnumbered/ip-interface
   866  	reqCtx := h.callsChannel.SendMultiRequest(&vpp_ip.IPUnnumberedDump{
   867  		SwIfIndex: ^interface_types.InterfaceIndex(0),
   868  	})
   869  
   870  	for {
   871  		unDetails := &vpp_ip.IPUnnumberedDetails{}
   872  		last, err := reqCtx.ReceiveReply(unDetails)
   873  		if last {
   874  			break
   875  		}
   876  		if err != nil {
   877  			return nil, err
   878  		}
   879  
   880  		unIfMap[uint32(unDetails.SwIfIndex)] = uint32(unDetails.IPSwIfIndex)
   881  	}
   882  
   883  	return unIfMap, nil
   884  }
   885  
   886  func (h *InterfaceVppHandler) dumpRxPlacement(interfaces map[uint32]*vppcalls.InterfaceDetails) error {
   887  	reqCtx := h.callsChannel.SendMultiRequest(&vpp_ifs.SwInterfaceRxPlacementDump{
   888  		SwIfIndex: interface_types.InterfaceIndex(^uint32(0)),
   889  	})
   890  	for {
   891  		rxDetails := &vpp_ifs.SwInterfaceRxPlacementDetails{}
   892  		stop, err := reqCtx.ReceiveReply(rxDetails)
   893  		if err != nil {
   894  			return fmt.Errorf("failed to dump rx-placement details: %v", err)
   895  		}
   896  		if stop {
   897  			break
   898  		}
   899  
   900  		ifData, ok := interfaces[uint32(rxDetails.SwIfIndex)]
   901  		if !ok {
   902  			h.log.Warnf("Received rx-placement data for unknown interface with index %d", rxDetails.SwIfIndex)
   903  			continue
   904  		}
   905  
   906  		ifData.Interface.RxModes = append(ifData.Interface.RxModes,
   907  			&ifs.Interface_RxMode{
   908  				Queue: rxDetails.QueueID,
   909  				Mode:  getRxModeType(rxDetails.Mode),
   910  			})
   911  
   912  		var worker uint32
   913  		if rxDetails.WorkerID > 0 {
   914  			worker = rxDetails.WorkerID - 1
   915  		}
   916  		ifData.Interface.RxPlacements = append(ifData.Interface.RxPlacements,
   917  			&ifs.Interface_RxPlacement{
   918  				Queue:      rxDetails.QueueID,
   919  				Worker:     worker,
   920  				MainThread: rxDetails.WorkerID == 0,
   921  			})
   922  	}
   923  	return nil
   924  }
   925  
   926  func dhcpAddressToString(address ip_types.Address, maskWidth uint32, isIPv6 bool) string {
   927  	dhcpIPByte := make([]byte, 16)
   928  	copy(dhcpIPByte[:], address.Un.XXX_UnionData[:])
   929  	if isIPv6 {
   930  		return fmt.Sprintf("%s/%d", net.IP(dhcpIPByte).To16().String(), maskWidth)
   931  	}
   932  	return fmt.Sprintf("%s/%d", net.IP(dhcpIPByte[:4]).To4().String(), maskWidth)
   933  }
   934  
   935  // guessInterfaceType attempts to guess the correct interface type from its internal name (as given by VPP).
   936  // This is required mainly for those interface types, that do not provide dump binary API,
   937  // such as loopback of af_packet.
   938  func guessInterfaceType(ifDevType, ifName string) ifs.Interface_Type {
   939  	switch {
   940  	case ifDevType == "RDMA interface":
   941  		return ifs.Interface_RDMA
   942  
   943  	case strings.HasPrefix(ifName, "loop"),
   944  		strings.HasPrefix(ifName, "local"):
   945  		return ifs.Interface_SOFTWARE_LOOPBACK
   946  
   947  	case strings.HasPrefix(ifName, "memif"):
   948  		return ifs.Interface_MEMIF
   949  
   950  	case strings.HasPrefix(ifName, "tap"),
   951  		strings.HasPrefix(ifName, "tun"):
   952  		return ifs.Interface_TAP
   953  
   954  	case strings.HasPrefix(ifName, "host"):
   955  		return ifs.Interface_AF_PACKET
   956  
   957  	case strings.HasPrefix(ifName, "vxlan"):
   958  		return ifs.Interface_VXLAN_TUNNEL
   959  
   960  	case strings.HasPrefix(ifName, "ipsec"):
   961  		return ifs.Interface_IPSEC_TUNNEL
   962  
   963  	case strings.HasPrefix(ifName, "vmxnet3"):
   964  		return ifs.Interface_VMXNET3_INTERFACE
   965  
   966  	case strings.HasPrefix(ifName, "Bond"):
   967  		return ifs.Interface_BOND_INTERFACE
   968  
   969  	case strings.HasPrefix(ifName, "gtpu"):
   970  		return ifs.Interface_GTPU_TUNNEL
   971  
   972  	case strings.HasPrefix(ifName, "ipip"):
   973  		return ifs.Interface_IPIP_TUNNEL
   974  
   975  	case strings.HasPrefix(ifName, "wireguard"):
   976  		return ifs.Interface_WIREGUARD_TUNNEL
   977  
   978  	default:
   979  		return ifs.Interface_DPDK
   980  	}
   981  }
   982  
   983  // memifModetoNB converts binary API type of memif mode to the northbound API type memif mode.
   984  func memifModetoNB(mode vpp_memif.MemifMode) ifs.MemifLink_MemifMode {
   985  	switch mode {
   986  	case vpp_memif.MEMIF_MODE_API_IP:
   987  		return ifs.MemifLink_IP
   988  	case vpp_memif.MEMIF_MODE_API_PUNT_INJECT:
   989  		return ifs.MemifLink_PUNT_INJECT
   990  	default:
   991  		return ifs.MemifLink_ETHERNET
   992  	}
   993  }
   994  
   995  // Convert binary API rx-mode to northbound representation
   996  func getRxModeType(mode interface_types.RxMode) ifs.Interface_RxMode_Type {
   997  	switch mode {
   998  	case 1:
   999  		return ifs.Interface_RxMode_POLLING
  1000  	case 2:
  1001  		return ifs.Interface_RxMode_INTERRUPT
  1002  	case 3:
  1003  		return ifs.Interface_RxMode_ADAPTIVE
  1004  	case 4:
  1005  		return ifs.Interface_RxMode_DEFAULT
  1006  	default:
  1007  		return ifs.Interface_RxMode_UNKNOWN
  1008  	}
  1009  }
  1010  
  1011  func getBondIfMode(mode vpp_bond.BondMode) ifs.BondLink_Mode {
  1012  	switch mode {
  1013  	case vpp_bond.BOND_API_MODE_ROUND_ROBIN:
  1014  		return ifs.BondLink_ROUND_ROBIN
  1015  	case vpp_bond.BOND_API_MODE_ACTIVE_BACKUP:
  1016  		return ifs.BondLink_ACTIVE_BACKUP
  1017  	case vpp_bond.BOND_API_MODE_XOR:
  1018  		return ifs.BondLink_XOR
  1019  	case vpp_bond.BOND_API_MODE_BROADCAST:
  1020  		return ifs.BondLink_BROADCAST
  1021  	case vpp_bond.BOND_API_MODE_LACP:
  1022  		return ifs.BondLink_LACP
  1023  	default:
  1024  		// UNKNOWN
  1025  		return 0
  1026  	}
  1027  }
  1028  
  1029  func getBondLoadBalance(lb vpp_bond.BondLbAlgo) ifs.BondLink_LoadBalance {
  1030  	switch lb {
  1031  	case vpp_bond.BOND_API_LB_ALGO_L34:
  1032  		return ifs.BondLink_L34
  1033  	case vpp_bond.BOND_API_LB_ALGO_L23:
  1034  		return ifs.BondLink_L23
  1035  	case vpp_bond.BOND_API_LB_ALGO_RR:
  1036  		return ifs.BondLink_RR
  1037  	case vpp_bond.BOND_API_LB_ALGO_BC:
  1038  		return ifs.BondLink_BC
  1039  	case vpp_bond.BOND_API_LB_ALGO_AB:
  1040  		return ifs.BondLink_AB
  1041  	default:
  1042  		return ifs.BondLink_L2
  1043  	}
  1044  }
  1045  
  1046  func getTagRwOption(op uint32) ifs.SubInterface_TagRewriteOptions {
  1047  	switch op {
  1048  	case 1:
  1049  		return ifs.SubInterface_PUSH1
  1050  	case 2:
  1051  		return ifs.SubInterface_PUSH2
  1052  	case 3:
  1053  		return ifs.SubInterface_POP1
  1054  	case 4:
  1055  		return ifs.SubInterface_POP2
  1056  	case 5:
  1057  		return ifs.SubInterface_TRANSLATE11
  1058  	case 6:
  1059  		return ifs.SubInterface_TRANSLATE12
  1060  	case 7:
  1061  		return ifs.SubInterface_TRANSLATE21
  1062  	case 8:
  1063  		return ifs.SubInterface_TRANSLATE22
  1064  	default: // disabled
  1065  		return ifs.SubInterface_DISABLED
  1066  	}
  1067  }
  1068  
  1069  func getGreTunnelType(tt vpp_gre.GreTunnelType) ifs.GreLink_Type {
  1070  	switch tt {
  1071  	case vpp_gre.GRE_API_TUNNEL_TYPE_L3:
  1072  		return ifs.GreLink_L3
  1073  	case vpp_gre.GRE_API_TUNNEL_TYPE_TEB:
  1074  		return ifs.GreLink_TEB
  1075  	case vpp_gre.GRE_API_TUNNEL_TYPE_ERSPAN:
  1076  		return ifs.GreLink_ERSPAN
  1077  	default:
  1078  		return ifs.GreLink_UNKNOWN
  1079  	}
  1080  }
  1081  
  1082  func getVxLanGpeProtocol(p ip_types.IPProto) ifs.VxlanLink_Gpe_Protocol {
  1083  
  1084  	// TODO: Fix conversion from IPProto, it seems those enums are incompatible now
  1085  
  1086  	switch p {
  1087  	case 1:
  1088  		return ifs.VxlanLink_Gpe_IP4
  1089  	case 2:
  1090  		return ifs.VxlanLink_Gpe_IP6
  1091  	case 3:
  1092  		return ifs.VxlanLink_Gpe_ETHERNET
  1093  	case 4:
  1094  		return ifs.VxlanLink_Gpe_NSH
  1095  	default:
  1096  		return ifs.VxlanLink_Gpe_UNKNOWN
  1097  	}
  1098  }
  1099  
  1100  func isAdminStateUp(flags interface_types.IfStatusFlags) bool {
  1101  	return flags&interface_types.IF_STATUS_API_FLAG_ADMIN_UP != 0
  1102  }
  1103  
  1104  func isLinkStateUp(flags interface_types.IfStatusFlags) bool {
  1105  	return flags&interface_types.IF_STATUS_API_FLAG_LINK_UP != 0
  1106  }
  1107  
  1108  func adminStateToInterfaceStatus(flags interface_types.IfStatusFlags) ifs.InterfaceState_Status {
  1109  	if isAdminStateUp(flags) {
  1110  		return ifs.InterfaceState_UP
  1111  	}
  1112  	return ifs.InterfaceState_DOWN
  1113  }
  1114  
  1115  func linkStateToInterfaceStatus(flags interface_types.IfStatusFlags) ifs.InterfaceState_Status {
  1116  	if isLinkStateUp(flags) {
  1117  		return ifs.InterfaceState_UP
  1118  	}
  1119  	return ifs.InterfaceState_DOWN
  1120  }