-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathport_set.py
161 lines (120 loc) · 3.81 KB
/
port_set.py
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
"""
Author(s): Pavel Krobot <[email protected]>
Copyright: (C) 2024 CESNET, z.s.p.o.
Module containing a class for grouping DPDK ports together.
"""
import collections
from .dpdk_port import DPDKPort
class DPDKPortSet:
"""Abstract class representing a set of DPDK ports.
Note that all ports must have the same duplex configuration,
otherwise it makes no sense to aggregate them.
Attributes
----------
ports : list(DPDKPort)
List of DPDK ports.
"""
def __init__(self, ports: list):
self._ports = ports
def __len__(self) -> int:
"""Get length of the port set.
Returns
-------
int
Length of the port set (i.e. count of ports in set).
"""
return len(self._ports)
def _aggregate_stats(self, extended=False):
total = collections.Counter()
for port in self._ports:
if extended:
stats = port.get_xstats()
else:
stats = port.get_stats()
total.update(stats)
return dict(total)
def get_stats(self) -> dict:
"""Aggregate DPDK port statistics from all ports.
Since each port can return a dictionary of tuples
with individual port statistics, it is necessary
to "merge" the tuples together. This is done by the
zip and sum functions.
Returns
-------
dict
Dictionary with port statistics aggregated from all ports.
"""
return self._aggregate_stats()
def clear_stats(self):
"""Clear statistics on all ports."""
for port in self._ports:
port.clear_stats()
def get_xstats(self) -> dict:
"""Aggregate extended statistics from all ports.
Returns
-------
dict
Dictionary with aggregated extended statistics from all
ports.
"""
return self._aggregate_stats(extended=True)
def clear_xstats(self):
"""Clear extended statistics on all ports."""
for port in self._ports:
port.clear_xstats()
@staticmethod
def _ports_duplex(statuses):
first = statuses[0]
# Check that link configuration is equal
for i in statuses:
if i["duplex"] != first["duplex"]:
raise RuntimeError(
f"Non-matching duplex mode detected: {i['duplex']} does not equal "
f"{first['duplex']}."
)
return first["duplex"]
def get_status(self) -> dict:
"""Aggregate port status from all ports into a single
dictionary.
Note that link status can only be UP when all ports are UP.
Otherwise, DOWN is reported.
The resulting dictionary follows the format:
```
{
"speed": int,
"duplex": str,
"status": str,
}
```
Returns
-------
dict
Dictionary with aggregated port status.
Raises
------
RuntimeError
The individual ports have not been configured the same way.
"""
statuses = [i.get_status() for i in self._ports]
# Derive link state
if all(x["port"] == "UP" for x in statuses):
state = "UP"
else:
state = "DOWN"
return {
"speed": sum([int(x["speed"]) for x in statuses]),
"duplex": self._ports_duplex(statuses),
"status": state,
}
def get_port(self, index) -> DPDKPort:
"""Get single port from set of ports by its index.
Parameters
----------
index : int
Index of requested port.
Returns
-------
DPDKPort
Requested port.
"""
return self._ports[index]