aboutsummaryrefslogtreecommitdiffstats
path: root/src/vpp-api/python/vpp_papi/vpp_papi.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/vpp-api/python/vpp_papi/vpp_papi.py')
-rw-r--r--src/vpp-api/python/vpp_papi/vpp_papi.py84
1 files changed, 65 insertions, 19 deletions
diff --git a/src/vpp-api/python/vpp_papi/vpp_papi.py b/src/vpp-api/python/vpp_papi/vpp_papi.py
index 5a9e0a70c64..30c00cd8dd3 100644
--- a/src/vpp-api/python/vpp_papi/vpp_papi.py
+++ b/src/vpp-api/python/vpp_papi/vpp_papi.py
@@ -18,7 +18,6 @@ from __future__ import print_function
from __future__ import absolute_import
import ctypes
import ipaddress
-import sys
import multiprocessing as mp
import os
import queue
@@ -30,6 +29,7 @@ import fnmatch
import weakref
import atexit
import time
+import pkg_resources
from .vpp_format import verify_enum_hint
from .vpp_serializer import VPPType, VPPEnumType, VPPEnumFlagType, VPPUnionType
from .vpp_serializer import VPPMessage, vpp_get_type, VPPTypeAlias
@@ -281,15 +281,28 @@ class VPPApiJSONFiles:
@classmethod
def process_json_file(self, apidef_file):
- return self._process_json(apidef_file.read())
+ api = json.load(apidef_file)
+ return self._process_json(api)
@classmethod
def process_json_str(self, json_str):
- return self._process_json(json_str)
+ api = json.loads(json_str)
+ return self._process_json(api)
+
+ @classmethod
+ def process_json_array_str(self, json_str):
+ services = {}
+ messages = {}
+
+ apis = json.loads(json_str)
+ for a in apis:
+ m, s = self._process_json(a)
+ messages.update(m)
+ services.update(s)
+ return messages, services
@staticmethod
- def _process_json(json_str): # -> Tuple[Dict, Dict]
- api = json.loads(json_str)
+ def _process_json(api): # -> Tuple[Dict, Dict]
types = {}
services = {}
messages = {}
@@ -373,7 +386,6 @@ class VPPApiJSONFiles:
try:
messages[m[0]] = VPPMessage(m[0], m[1:])
except VPPNotImplementedError:
- ### OLE FIXME
logger.error("Not implemented error for {}".format(m[0]))
except KeyError:
pass
@@ -435,6 +447,7 @@ class VPPApiClient:
read_timeout=5,
use_socket=True,
server_address="/run/vpp/api.sock",
+ bootstrapapi=False,
):
"""Create a VPP API object.
@@ -472,25 +485,37 @@ class VPPApiClient:
self.server_address = server_address
self._apifiles = apifiles
self.stats = {}
+ self.bootstrapapi = bootstrapapi
- if self.apidir is None and hasattr(self.__class__, "apidir"):
- # Keep supporting the old style of providing apidir.
- self.apidir = self.__class__.apidir
- try:
- self.apifiles, self.messages, self.services = VPPApiJSONFiles.load_api(
- apifiles, self.apidir
+ if not bootstrapapi:
+ if self.apidir is None and hasattr(self.__class__, "apidir"):
+ # Keep supporting the old style of providing apidir.
+ self.apidir = self.__class__.apidir
+ try:
+ self.apifiles, self.messages, self.services = VPPApiJSONFiles.load_api(
+ apifiles, self.apidir
+ )
+ except VPPRuntimeError as e:
+ if testmode:
+ self.apifiles = []
+ else:
+ raise e
+ else:
+ # Bootstrap the API (memclnt.api bundled with VPP PAPI)
+ resource_path = "/".join(("data", "memclnt.api.json"))
+ file_content = pkg_resources.resource_string(__name__, resource_path)
+ self.messages, self.services = VPPApiJSONFiles.process_json_str(
+ file_content
)
- except VPPRuntimeError as e:
- if testmode:
- self.apifiles = []
- else:
- raise e
# Basic sanity check
if len(self.messages) == 0 and not testmode:
raise VPPValueError(1, "Missing JSON message definitions")
- if not (verify_enum_hint(VppEnum.vl_api_address_family_t)):
- raise VPPRuntimeError("Invalid address family hints. " "Cannot continue.")
+ if not bootstrapapi:
+ if not (verify_enum_hint(VppEnum.vl_api_address_family_t)):
+ raise VPPRuntimeError(
+ "Invalid address family hints. " "Cannot continue."
+ )
self.transport = VppTransport(
self, read_timeout=read_timeout, server_address=server_address
@@ -573,6 +598,21 @@ class VPPApiClient:
else:
self.logger.debug("No such message type or failed CRC checksum: %s", n)
+ def get_api_definitions(self):
+ """get_api_definition. Bootstrap from the embedded memclnt.api.json file."""
+
+ # Bootstrap so we can call the get_api_json function
+ self._register_functions(do_async=False)
+
+ r = self.api.get_api_json()
+ if r.retval != 0:
+ raise VPPApiError("Failed to load API definitions from VPP")
+
+ # Process JSON
+ m, s = VPPApiJSONFiles.process_json_array_str(r.json)
+ self.messages.update(m)
+ self.services.update(s)
+
def connect_internal(self, name, msg_handler, chroot_prefix, rx_qlen, do_async):
pfx = chroot_prefix.encode("utf-8") if chroot_prefix else None
@@ -580,6 +620,10 @@ class VPPApiClient:
if rv != 0:
raise VPPIOError(2, "Connect failed")
self.vpp_dictionary_maxid = self.transport.msg_table_max_index()
+
+ # Register functions
+ if self.bootstrapapi:
+ self.get_api_definitions()
self._register_functions(do_async=do_async)
# Initialise control ping
@@ -588,6 +632,7 @@ class VPPApiClient:
("control_ping" + "_" + crc[2:])
)
self.control_ping_msgdef = self.messages["control_ping"]
+
if self.async_thread:
self.event_thread = threading.Thread(target=self.thread_msg_handler)
self.event_thread.daemon = True
@@ -659,6 +704,7 @@ class VPPApiClient:
)
(i, ci, context), size = header.unpack(msg, 0)
+
if self.id_names[i] == "rx_thread_exit":
return