aboutsummaryrefslogtreecommitdiffstats
path: root/api/ifcounters/ifcounters.go
blob: 202fe6ea763a427fa02bb083cda6c0875913341f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright (c) 2017 Cisco and/or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ifcounters

import (
	"bytes"
	"errors"
	"fmt"

	"github.com/lunixbochs/struc"
)

// VnetInterfaceCounters is the input data type defined in the 'interface.api', with binary encoded Data field,
// that can be decoded into the InterfaceCounter or CombinedInterfaceCounter struct using this package.
type VnetInterfaceCounters struct {
	VnetCounterType uint8
	IsCombined      uint8
	FirstSwIfIndex  uint32
	Count           uint32 `struc:"sizeof=Data"`
	Data            []byte
}

// CounterType is the basic counter type - contains only packet statistics.
type CounterType int

// constants as defined in the vnet_interface_counter_type_t enum in 'vnet/interface.h'
const (
	Drop    CounterType = 0
	Punt                = 1
	IPv4                = 2
	IPv6                = 3
	RxNoBuf             = 4
	RxMiss              = 5
	RxError             = 6
	TxError             = 7
	MPLS                = 8
)

// CombinedCounterType is the extended counter type - contains both packet and byte statistics.
type CombinedCounterType int

// constants as defined in the vnet_interface_counter_type_t enum in 'vnet/interface.h'
const (
	Rx CombinedCounterType = 0
	Tx                     = 1
)

// InterfaceCounter contains basic counter data (contains only packet statistics).
type InterfaceCounter struct {
	Type      CounterType
	SwIfIndex uint32
	Packets   uint64
}

// CombinedInterfaceCounter contains extended counter data (contains both packet and byte statistics).
type CombinedInterfaceCounter struct {
	Type      CombinedCounterType
	SwIfIndex uint32
	Packets   uint64
	Bytes     uint64
}

type counterData struct {
	Packets uint64
}

type counter struct {
	Count uint32 `struc:"sizeof=Data"`
	Data  []counterData
}

type combinedCounterData struct {
	Packets uint64
	Bytes   uint64
}

type combinedCounter struct {
	Count uint32 `struc:"sizeof=Data"`
	Data  []combinedCounterData
}

// DecodeCounters decodes VnetInterfaceCounters struct content into the slice of InterfaceCounter structs.
func DecodeCounters(vnetCounters VnetInterfaceCounters) ([]InterfaceCounter, error) {
	if vnetCounters.IsCombined == 1 {
		return nil, errors.New("invalid argument - combined counter passed in")
	}

	// decode into internal struct
	var c counter
	buf := bytes.NewReader(vnetCounters.Data)
	err := struc.Unpack(buf, &c)
	if err != nil {
		return nil, fmt.Errorf("unable to decode counter data: %v", err)
	}

	// prepare the slice
	res := make([]InterfaceCounter, c.Count)

	// fill in the slice
	for i := uint32(0); i < c.Count; i++ {
		res[i].Type = CounterType(vnetCounters.VnetCounterType)
		res[i].SwIfIndex = vnetCounters.FirstSwIfIndex + i
		res[i].Packets = c.Data[i].Packets
	}

	return res, nil
}

// DecodeCombinedCounters decodes VnetInterfaceCounters struct content into the slice of CombinedInterfaceCounter structs.
func DecodeCombinedCounters(vnetCounters VnetInterfaceCounters) ([]CombinedInterfaceCounter, error) {
	if vnetCounters.IsCombined != 1 {
		return nil, errors.New("invalid argument - simple counter passed in")
	}

	// decode into internal struct
	var c combinedCounter
	buf := bytes.NewReader(vnetCounters.Data)
	err := struc.Unpack(buf, &c)
	if err != nil {
		return nil, fmt.Errorf("unable to decode counter data: %v", err)
	}

	// prepare the slice
	res := make([]CombinedInterfaceCounter, c.Count)

	// fill in the slice
	for i := uint32(0); i < c.Count; i++ {
		res[i].Type = CombinedCounterType(vnetCounters.VnetCounterType)
		res[i].SwIfIndex = vnetCounters.FirstSwIfIndex + i
		res[i].Packets = c.Data[i].Packets
		res[i].Bytes = c.Data[i].Bytes
	}

	return res, nil
}