go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/puntplugin/vppcalls/vpp2101/dump_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  	"net"
    19  	"strings"
    20  
    21  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/interface_types"
    22  	vpp_ip "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/ip"
    23  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/ip_types"
    24  	vpp_punt "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/punt"
    25  	"go.ligato.io/vpp-agent/v3/plugins/vpp/puntplugin/vppcalls"
    26  	punt "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/punt"
    27  )
    28  
    29  // DumpPuntRedirect dumps ip redirect punts
    30  func (h *PuntVppHandler) DumpPuntRedirect() (punts []*punt.IPRedirect, err error) {
    31  	punt4, err := h.dumpPuntRedirect(false)
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  	punts = append(punts, punt4...)
    36  
    37  	punt6, err := h.dumpPuntRedirect(true)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	punts = append(punts, punt6...)
    42  
    43  	return punts, nil
    44  }
    45  
    46  func (h *PuntVppHandler) dumpPuntRedirect(ipv6 bool) (punts []*punt.IPRedirect, err error) {
    47  	req := h.callsChannel.SendMultiRequest(&vpp_ip.IPPuntRedirectDump{
    48  		SwIfIndex: ^interface_types.InterfaceIndex(0),
    49  		IsIPv6:    ipv6,
    50  	})
    51  	for {
    52  		d := &vpp_ip.IPPuntRedirectDetails{}
    53  		stop, err := req.ReceiveReply(d)
    54  		if stop {
    55  			break
    56  		}
    57  		if err != nil {
    58  			return nil, err
    59  		}
    60  
    61  		rxIface, _, exists := h.ifIndexes.LookupBySwIfIndex(uint32(d.Punt.RxSwIfIndex))
    62  		if !exists {
    63  			h.log.Warnf("RX interface (%v) not found", d.Punt.RxSwIfIndex)
    64  			continue
    65  		}
    66  		txIface, _, exists := h.ifIndexes.LookupBySwIfIndex(uint32(d.Punt.TxSwIfIndex))
    67  		if !exists {
    68  			h.log.Warnf("TX interface (%v) not found", d.Punt.TxSwIfIndex)
    69  			continue
    70  		}
    71  
    72  		var l3proto punt.L3Protocol
    73  		var nextHop string
    74  
    75  		if d.Punt.Nh.Af == ip_types.ADDRESS_IP4 {
    76  			l3proto = punt.L3Protocol_IPV4
    77  			addr := d.Punt.Nh.Un.GetIP4()
    78  			nextHop = net.IP(addr[:]).To4().String()
    79  		} else if d.Punt.Nh.Af == ip_types.ADDRESS_IP6 {
    80  			l3proto = punt.L3Protocol_IPV6
    81  			addr := d.Punt.Nh.Un.GetIP6()
    82  			nextHop = net.IP(addr[:]).To16().String()
    83  		} else {
    84  			h.log.Warnf("invalid address family (%v)", d.Punt.Nh.Af)
    85  			continue
    86  		}
    87  
    88  		punts = append(punts, &punt.IPRedirect{
    89  			L3Protocol:  l3proto,
    90  			RxInterface: rxIface,
    91  			TxInterface: txIface,
    92  			NextHop:     nextHop,
    93  		})
    94  	}
    95  
    96  	return punts, nil
    97  }
    98  
    99  // DumpExceptions returns dump of registered punt exceptions.
   100  func (h *PuntVppHandler) DumpExceptions() (punts []*vppcalls.ExceptionDetails, err error) {
   101  	reasons, err := h.dumpPuntReasons()
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	reasonMap := make(map[uint32]string, len(reasons))
   106  	for _, r := range reasons {
   107  		reasonMap[r.ID] = r.Reason.Name
   108  	}
   109  
   110  	if punts, err = h.dumpPuntExceptions(reasonMap); err != nil {
   111  		return nil, err
   112  	}
   113  
   114  	return punts, nil
   115  }
   116  
   117  func (h *PuntVppHandler) dumpPuntExceptions(reasons map[uint32]string) (punts []*vppcalls.ExceptionDetails, err error) {
   118  	req := h.callsChannel.SendMultiRequest(&vpp_punt.PuntSocketDump{
   119  		Type: vpp_punt.PUNT_API_TYPE_EXCEPTION,
   120  	})
   121  	for {
   122  		d := &vpp_punt.PuntSocketDetails{}
   123  		stop, err := req.ReceiveReply(d)
   124  		if stop {
   125  			break
   126  		}
   127  		if err != nil {
   128  			return nil, err
   129  		}
   130  
   131  		if d.Punt.Type != vpp_punt.PUNT_API_TYPE_EXCEPTION {
   132  			h.log.Warnf("VPP returned invalid punt type in exception punt dump: %v", d.Punt.Type)
   133  			continue
   134  		}
   135  
   136  		puntData := d.Punt.Punt.GetException()
   137  		reason := reasons[puntData.ID]
   138  		socketPath := strings.Trim(d.Pathname, "\x00")
   139  
   140  		punts = append(punts, &vppcalls.ExceptionDetails{
   141  			Exception: &punt.Exception{
   142  				Reason:     reason,
   143  				SocketPath: vppConfigSocketPath,
   144  			},
   145  			SocketPath: socketPath,
   146  		})
   147  	}
   148  
   149  	return punts, nil
   150  }
   151  
   152  // DumpRegisteredPuntSockets returns punt to host via registered socket entries
   153  func (h *PuntVppHandler) DumpRegisteredPuntSockets() (punts []*vppcalls.PuntDetails, err error) {
   154  	if punts, err = h.dumpPuntL4(); err != nil {
   155  		return nil, err
   156  	}
   157  
   158  	return punts, nil
   159  }
   160  
   161  func (h *PuntVppHandler) dumpPuntL4() (punts []*vppcalls.PuntDetails, err error) {
   162  	req := h.callsChannel.SendMultiRequest(&vpp_punt.PuntSocketDump{
   163  		Type: vpp_punt.PUNT_API_TYPE_L4,
   164  	})
   165  	for {
   166  		d := &vpp_punt.PuntSocketDetails{}
   167  		stop, err := req.ReceiveReply(d)
   168  		if stop {
   169  			break
   170  		}
   171  		if err != nil {
   172  			return nil, err
   173  		}
   174  
   175  		if d.Punt.Type != vpp_punt.PUNT_API_TYPE_L4 {
   176  			h.log.Warnf("VPP returned invalid punt type in L4 punt dump: %v", d.Punt.Type)
   177  			continue
   178  		}
   179  
   180  		puntData := d.Punt.Punt.GetL4()
   181  		socketPath := strings.Trim(d.Pathname, "\x00")
   182  
   183  		punts = append(punts, &vppcalls.PuntDetails{
   184  			PuntData: &punt.ToHost{
   185  				Port:       uint32(puntData.Port),
   186  				L3Protocol: parseL3Proto(puntData.Af),
   187  				L4Protocol: parseL4Proto(puntData.Protocol),
   188  				SocketPath: vppConfigSocketPath,
   189  			},
   190  			SocketPath: socketPath,
   191  		})
   192  	}
   193  
   194  	return punts, nil
   195  }
   196  
   197  // DumpPuntReasons returns all known punt reasons from VPP
   198  func (h *PuntVppHandler) DumpPuntReasons() (reasons []*vppcalls.ReasonDetails, err error) {
   199  	if reasons, err = h.dumpPuntReasons(); err != nil {
   200  		return nil, err
   201  	}
   202  
   203  	return reasons, nil
   204  }
   205  
   206  func (h *PuntVppHandler) dumpPuntReasons() (reasons []*vppcalls.ReasonDetails, err error) {
   207  	req := h.callsChannel.SendMultiRequest(&vpp_punt.PuntReasonDump{})
   208  	for {
   209  		d := &vpp_punt.PuntReasonDetails{}
   210  		stop, err := req.ReceiveReply(d)
   211  		if stop {
   212  			break
   213  		}
   214  		if err != nil {
   215  			return nil, err
   216  		}
   217  
   218  		reasons = append(reasons, &vppcalls.ReasonDetails{
   219  			Reason: &punt.Reason{
   220  				Name: d.Reason.Name,
   221  			},
   222  			ID: d.Reason.ID,
   223  		})
   224  	}
   225  
   226  	return reasons, nil
   227  }
   228  
   229  func parseL3Proto(p ip_types.AddressFamily) punt.L3Protocol {
   230  	switch p {
   231  	case ip_types.ADDRESS_IP4:
   232  		return punt.L3Protocol_IPV4
   233  	case ip_types.ADDRESS_IP6:
   234  		return punt.L3Protocol_IPV6
   235  	}
   236  	return punt.L3Protocol_UNDEFINED_L3
   237  }
   238  
   239  func parseL4Proto(p ip_types.IPProto) punt.L4Protocol {
   240  	switch p {
   241  	case ip_types.IP_API_PROTO_TCP:
   242  		return punt.L4Protocol_TCP
   243  	case ip_types.IP_API_PROTO_UDP:
   244  		return punt.L4Protocol_UDP
   245  	}
   246  	return punt.L4Protocol_UNDEFINED_L4
   247  }