summaryrefslogtreecommitdiffstats
path: root/src/vppinfra/tw_timer_16t_1w_2048sl.h
AgeCommit message (Expand)AuthorFilesLines
2019-04-08host stack: update stale copyrightFlorin Coras1-1/+1
2018-12-19tw: fix _16t_1w_2048sl timer weel definitionFlorin Coras1-3/+3
2017-09-01Add fixed-size, preallocated pool supportDave Barach1-0/+1
2017-06-28switch vlib process model to tw_timer_template timer implDave Barach1-0/+4
2017-06-12three-level timer wheel implementation w/ overflow vectorDave Barach1-0/+1
2017-03-01VPP-598: tcp stack initial commitDave Barach1-0/+46
ef='#n149'>149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
package main

import (
	"flag"
	"fmt"
	"git.fd.io/govpp.git"
	"git.fd.io/govpp.git/adapter"
	"git.fd.io/govpp.git/adapter/vppapiclient"
	"git.fd.io/govpp.git/api"
	"git.fd.io/govpp.git/core"
	"git.fd.io/govpp.git/examples/bin_api/interfaces"
	"git.fd.io/govpp.git/examples/bin_api/vpe"
	"log"
)

//////////////////////////////////////
/////////   Data structs   ///////////
//////////////////////////////////////

const defaultStatsSocketPath = "/run/vpp/stats.sock"
const defaultShmPrefix = ""

func parseMacAddress(l2Address []byte, l2AddressLength uint32) string {
	var mac string
	for i := uint32(0); i < l2AddressLength; i++ {
		mac += fmt.Sprintf("%02x", l2Address[i])
		if i < l2AddressLength-1 {
			mac += ":"
		}
	}
	return mac
}

type interfaceStats struct {
	TxBytes   uint64
	TxPackets uint64
	TxErrors  uint64
	RxBytes   uint64
	RxPackets uint64
	RxErrors  uint64
	Drops     uint64
	Punts     uint64
}

type vppInterface struct {
	interfaces.SwInterfaceDetails
	Stats interfaceStats
}

type vppConnector struct {
	statsSocketPath string
	shmPrefix       string

	conn  *core.Connection
	api   api.Channel
	stats adapter.StatsAPI

	VppDetails vpe.ShowVersionReply
	Interfaces []*vppInterface
}

//////////////////////////////////////
/////////   VPP workflow   ///////////
//////////////////////////////////////

func (v *vppConnector) getVppVersion() error {
	if err := v.api.SendRequest(&vpe.ShowVersion{}).ReceiveReply(&v.VppDetails); err != nil {
		return fmt.Errorf("failed to fetch vpp version: %v", err)
	}
	return nil
}

func (v *vppConnector) getInterfaces() error {
	ifCtx := v.api.SendMultiRequest(&interfaces.SwInterfaceDump{})
	for {
		ifDetails := interfaces.SwInterfaceDetails{}
		stop, err := ifCtx.ReceiveReply(&ifDetails)
		if err != nil {
			return fmt.Errorf("failed to fetch vpp interface: %v", err)
		}
		if stop {
			break
		}

		v.Interfaces = append(v.Interfaces, &vppInterface{SwInterfaceDetails: ifDetails})
	}
	return nil
}

func (v *vppConnector) connect() (err error) {
	if v.conn, err = govpp.Connect(v.shmPrefix); err != nil {
		return fmt.Errorf("failed to connect to vpp: %v", err)
	}

	if v.api, err = v.conn.NewAPIChannel(); err != nil {
		return fmt.Errorf("failed to create api channel: %v", err)
	}

	v.stats = vppapiclient.NewStatClient(v.statsSocketPath)
	if err = v.stats.Connect(); err != nil {
		return fmt.Errorf("failed to connect to Stats adapter: %v", err)
	}

	return
}

func (v *vppConnector) disconnect() {
	if v.stats != nil {
		v.stats.Disconnect()
	}
	if v.conn != nil {
		v.conn.Disconnect()
	}
}

func (v *vppConnector) reduceCombinedCounters(stat *adapter.StatEntry) *[]adapter.CombinedCounter {
	counters := stat.Data.(adapter.CombinedCounterStat)
	stats := make([]adapter.CombinedCounter, len(v.Interfaces))
	for _, workerStats := range counters {
		for i := 0; i < len(v.Interfaces); i++ {
			stats[i].Bytes += workerStats[i].Bytes
			stats[i].Packets += workerStats[i].Packets
		}
	}
	return &stats
}

func (v *vppConnector) reduceSimpleCounters(stat *adapter.StatEntry) *[]adapter.Counter {
	counters := stat.Data.(adapter.SimpleCounterStat)
	stats := make([]adapter.Counter, len(v.Interfaces))
	for _, workerStats := range counters {
		for i := 0; i < len(v.Interfaces); i++ {
			stats[i] += workerStats[i]
		}
	}
	return &stats
}

func (v *vppConnector) getStatsForAllInterfaces() error {
	statsDump, err := v.stats.DumpStats("/if")
	if err != nil {
		return fmt.Errorf("failed to dump vpp Stats: %v", err)
	}

	stats := func(i int) *interfaceStats { return &v.Interfaces[uint32(i)].Stats }

	for _, stat := range statsDump {
		switch stat.Name {
		case "/if/tx":
			{
				for i, counter := range *v.reduceCombinedCounters(stat) {
					stats(i).TxBytes = uint64(counter.Bytes)
					stats(i).TxPackets = uint64(counter.Packets)
				}
			}
		case "/if/rx":
			{
				for i, counter := range *v.reduceCombinedCounters(stat) {
					stats(i).RxBytes = uint64(counter.Bytes)
					stats(i).RxPackets = uint64(counter.Packets)
				}
			}
		case "/if/tx-error":
			{
				for i, counter := range *v.reduceSimpleCounters(stat) {
					stats(i).TxErrors = uint64(counter)
				}
			}
		case "/if/rx-error":
			{
				for i, counter := range *v.reduceSimpleCounters(stat) {
					stats(i).RxErrors = uint64(counter)
				}
			}
		case "/if/drops":
			{
				for i, counter := range *v.reduceSimpleCounters(stat) {
					stats(i).Drops = uint64(counter)
				}
			}
		case "/if/punt":
			{
				for i, counter := range *v.reduceSimpleCounters(stat) {
					stats(i).Punts = uint64(counter)
				}
			}
		}
	}
	return nil
}

//////////////////////////////////////

func main() {
	statsSocketPathPtr := flag.String("stats_socket_path", defaultStatsSocketPath, "Path to vpp stats socket")
	shmPrefixPtr := flag.String("shm_prefix", defaultShmPrefix, "Shared memory prefix (advanced)")
	flag.Parse()

	vppConn := &vppConnector{statsSocketPath: *statsSocketPathPtr, shmPrefix: *shmPrefixPtr}
	defer vppConn.disconnect()

	if err := vppConn.connect(); err != nil {
		log.Fatalln(err)
	}

	if err := vppConn.getVppVersion(); err != nil {
		log.Fatalln(err)
	}

	if err := vppConn.getInterfaces(); err != nil {
		log.Fatalln(err)
	}

	if err := vppConn.getStatsForAllInterfaces(); err != nil {
		log.Fatalln(err)
	}

	jsonString, err := dumpToJSONString(vppConn)
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println(jsonString)
}