Newer
Older
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
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
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# 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.
"""
P4Runtime global options.
"""
import enum
try:
from .p4_exception import UnknownOptionName, InvalidOptionValueType
except ImportError:
from p4_exception import UnknownOptionName, InvalidOptionValueType
@enum.unique
class Options(enum.Enum):
"""
P4 options.
"""
canonical_bytestrings = bool
class GlobalOptions:
"""
P4 global options.
"""
option_defaults = {
Options.canonical_bytestrings: True,
}
option_helpstrings = {
Options.canonical_bytestrings: """
Use byte-padded legacy format for binary strings sent to the P4Runtime server,
instead of the canonical representation. See P4Runtime specification for details.
"""
}
def __init__(self):
self._values = {}
self.reset()
self._option_names = [option.name for option in Options]
self._set_docstring()
def reset(self):
"""
Reset all options to their defaults.
:return: void
"""
for option in Options:
assert option in GlobalOptions.option_defaults
self._values[option] = GlobalOptions.option_defaults[option]
def _supported_options_as_str(self):
"""
Return a comma-separated string of supported options.
:return: string of supported options
"""
return ", ".join([f"{o.name} ({o.value.__name__})" for o in Options])
def _supported_options_as_str_verbose(self):
"""
Return a detailed comma-separated string of supported options.
:return: string of supported options
"""
opt_str = ""
for option in Options:
opt_str += f"Option name: {option.name}\n"
opt_str += f"Type: {option.value.__name__}\n"
opt_str += f"Default value: " \
f"{GlobalOptions.option_defaults[option]}\n"
opt_str += f"Description: " \
f"{GlobalOptions.option_helpstrings.get(option, 'N/A')}\n"
opt_str += "\n"
return opt_str[:-1]
def _set_docstring(self):
"""
Set the documentation for this object.
:return: void
"""
self.__doc__ = f"""
Manage global options for the P4Runtime shell.
Supported options are: {self._supported_options_as_str()}
To set the value of a global option, use GLOBAL_OPTIONS["<option name>"] = <option value>
To access the current value of a global option, use GLOBAL_OPTIONS.["<option name>"]
To reset all options to their default value, use GLOBAL_OPTIONS.reset
{self._supported_options_as_str_verbose()}
"""
def __dir__(self):
"""
Return all names in this scope.
:return: list of names in scope
"""
return ["reset", "set", "get"]
def set_option(self, option, value):
"""
Set an option's value.
:param option: option to set
:param value: option value
:return: void
"""
self._values[option] = value
def get_option(self, option):
"""
Get an option's value.
:param option: option to get
:return: option value
"""
return self._values[option]
def set(self, name, value):
"""
Create an option and set its value.
:param name: option name
:param value: option value
:return: void
"""
try:
option = Options[name]
except KeyError as ex:
raise UnknownOptionName(name) from ex
if not isinstance(value, option.value):
raise InvalidOptionValueType(option, value)
self.set_option(option, value)
def get(self, name):
"""
Get option by name.
:param name: option name
:return: option
"""
try:
option = Options[name]
except KeyError as ex:
raise UnknownOptionName(name) from ex
return self.get_option(option)
def __setitem__(self, name, value):
self.set(name, value)
def __getitem__(self, name):
return self.get(name)
def __str__(self):
return '\n'.join([f"{o.name}: {v}" for o, v in self._values.items()])
GLOBAL_OPTIONS = GlobalOptions()
def to_canonical_bytes(bytes_):
"""
Convert to canonical bytes.
:param bytes_: byte stream
:return: canonical bytes
"""
if len(bytes_) == 0:
return bytes_
num_zeros = 0
for byte in bytes_:
if byte != 0:
break
num_zeros += 1
if num_zeros == len(bytes_):
return bytes_[:1]
return bytes_[num_zeros:]
def make_canonical_if_option_set(bytes_):
"""
Convert to canonical bytes if option is set.
:param bytes_: byte stream
:return: canonical bytes
"""
if GLOBAL_OPTIONS.get_option(Options.canonical_bytestrings):
return to_canonical_bytes(bytes_)
return bytes_