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
# 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 manager.
"""
import enum
import os
import queue
import time
import logging
from collections import Counter, OrderedDict
from threading import Thread
from tabulate import tabulate
from p4.v1 import p4runtime_pb2
from p4.config.v1 import p4info_pb2
try:
from .p4_client import P4RuntimeClient, P4RuntimeException,\
P4RuntimeWriteException, WriteOperation, parse_p4runtime_error
from .p4_context import P4RuntimeEntity, P4Type, Context
from .p4_global_options import make_canonical_if_option_set
from .p4_common import encode,\
parse_resource_string_from_json, parse_resource_integer_from_json,\
parse_resource_bytes_from_json, parse_match_operations_from_json,\
parse_action_parameters_from_json, parse_integer_list_from_json
from .p4_exception import UserError, InvalidP4InfoError
except ImportError:
from p4_client import P4RuntimeClient, P4RuntimeException,\
P4RuntimeWriteException, WriteOperation, parse_p4runtime_error
from p4_context import P4RuntimeEntity, P4Type, Context
from p4_global_options import make_canonical_if_option_set
from p4_common import encode,\
parse_resource_string_from_json, parse_resource_integer_from_json,\
parse_resource_bytes_from_json, parse_match_operations_from_json,\
parse_action_parameters_from_json, parse_integer_list_from_json
from p4_exception import UserError, InvalidP4InfoError
# Logger instance
LOGGER = logging.getLogger(__name__)
# Global P4Runtime context
CONTEXT = Context()
# Global P4Runtime client
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
# Constant P4 entities
KEY_TABLE = "table"
KEY_ACTION = "action"
KEY_ACTION_PROFILE = "action_profile"
KEY_COUNTER = "counter"
KEY_DIR_COUNTER = "direct_counter"
KEY_METER = "meter"
KEY_DIR_METER = "direct_meter"
KEY_CTL_PKT_METADATA = "controller_packet_metadata"
def get_context():
"""
Return P4 context.
:return: context object
"""
return CONTEXT
def get_table_type(table):
"""
Assess the type of P4 table based upon the matching scheme.
:param table: P4 table
:return: P4 table type
"""
for m_f in table.match_fields:
if m_f.match_type == p4info_pb2.MatchField.EXACT:
return p4info_pb2.MatchField.EXACT
if m_f.match_type == p4info_pb2.MatchField.LPM:
return p4info_pb2.MatchField.LPM
if m_f.match_type == p4info_pb2.MatchField.TERNARY:
return p4info_pb2.MatchField.TERNARY
if m_f.match_type == p4info_pb2.MatchField.RANGE:
return p4info_pb2.MatchField.RANGE
if m_f.match_type == p4info_pb2.MatchField.OPTIONAL:
return p4info_pb2.MatchField.OPTIONAL
return None
def match_type_to_str(match_type):
"""
Convert table match type to string.
:param match_type: table match type object
:return: table match type string
"""
if match_type == p4info_pb2.MatchField.EXACT:
return "Exact"
if match_type == p4info_pb2.MatchField.LPM:
return "LPM"
if match_type == p4info_pb2.MatchField.TERNARY:
return "Ternary"
if match_type == p4info_pb2.MatchField.RANGE:
return "Range"
if match_type == p4info_pb2.MatchField.OPTIONAL:
return "Optional"
return None
class P4Manager:
"""
Class to manage the runtime entries of a P4 pipeline.
"""
def __init__(self, device_id: int, ip_address: str, port: int,
election_id: tuple, role_name=None, ssl_options=None):
self.__id = device_id
self.__ip_address = ip_address
self.__port = int(port)
self.__endpoint = f"{self.__ip_address}:{self.__port}"
self.key_id = ip_address+str(port)
CLIENTS[self.key_id] = P4RuntimeClient(
self.__id, self.__endpoint, election_id, role_name, ssl_options)
self.__p4info = None
self.local_client = CLIENTS[self.key_id]
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
# Internal memory for whitebox management
# | -> P4 entities
self.p4_objects = {}
# | -> P4 entities
self.table_entries = {}
self.counter_entries = {}
self.direct_counter_entries = {}
self.meter_entries = {}
self.direct_meter_entries = {}
self.multicast_groups = {}
self.clone_session_entries = {}
self.action_profile_members = {}
self.action_profile_groups = {}
def start(self, p4bin_path, p4info_path):
"""
Start the P4 manager. This involves:
(i) setting the forwarding pipeline of the target switch,
(ii) creating a P4 context object,
(iii) Discovering all the entities of the pipeline, and
(iv) initializing necessary data structures of the manager
:param p4bin_path: Path to the P4 binary file
:param p4info_path: Path to the P4 info file
:return: void
"""
if not p4bin_path or not os.path.exists(p4bin_path):
LOGGER.warning("P4 binary file not found")
if not p4info_path or not os.path.exists(p4info_path):
LOGGER.warning("P4 info file not found")
# Forwarding pipeline is only set iff both files are present
if p4bin_path and p4info_path:
try:
self.local_client.set_fwd_pipe_config(p4info_path, p4bin_path)
except FileNotFoundError as ex:
LOGGER.critical(ex)
self.local_client.tear_down()
raise FileNotFoundError(ex) from ex
except P4RuntimeException as ex:
LOGGER.critical("Error when setting config")
LOGGER.critical(ex)
self.local_client.tear_down()
raise P4RuntimeException(ex) from ex
except Exception as ex: # pylint: disable=broad-except
LOGGER.critical("Error when setting config")
self.local_client.tear_down()
raise Exception(ex) from ex
try:
self.__p4info = self.local_client.get_p4info()
except P4RuntimeException as ex:
LOGGER.critical("Error when retrieving P4Info")
LOGGER.critical(ex)
self.local_client.tear_down()
Loading
Loading full blame…