-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (c) 2016 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
self._api = VppApiDynamicMethodHolder()
for name, msg in vpp_iterator(self.messages):
n = name + '_' + msg.crc[2:]
- i = self.transport.get_msg_index(n.encode('utf-8'))
+ i = self.transport.get_msg_index(n)
if i > 0:
self.id_msgdef[i] = msg
self.id_names[i] = name
do_async):
pfx = chroot_prefix.encode('utf-8') if chroot_prefix else None
- rv = self.transport.connect(name.encode('utf-8'), pfx,
+ rv = self.transport.connect(name, pfx,
msg_handler, rx_qlen)
if rv != 0:
raise VPPIOError(2, 'Connect failed')
# Initialise control ping
crc = self.messages['control_ping'].crc
self.control_ping_index = self.transport.get_msg_index(
- ('control_ping' + '_' + crc[2:]).encode('utf-8'))
+ ('control_ping' + '_' + crc[2:]))
self.control_ping_msgdef = self.messages['control_ping']
if self.async_thread:
self.event_thread = threading.Thread(
# Block until we get a reply.
rl = []
while (True):
- msg = self.transport.read()
- if not msg:
+ r = self.read_blocking(no_type_conversion)
+ if r is None:
raise VPPIOError(2, 'VPP API client: read failed')
- r = self.decode_incoming_msg(msg, no_type_conversion)
msgname = type(r).__name__
if context not in r or r.context == 0 or context != r.context:
# Message being queued
self.transport.resume()
- self.logger.debug('Return from {!r}'.format(r))
+ s = 'Return value: {!r}'.format(r)
+ if len(s) > 80:
+ s = s[:80] + "..."
+ self.logger.debug(s)
return rl
def _call_vpp_async(self, i, msg, **kwargs):
- """Given a message, send the message and await a reply.
+ """Given a message, send the message and return the context.
msgdef - the message packing definition
i - the message type index
context - context number - chosen at random if not
supplied.
The remainder of the kwargs are the arguments to the API call.
+
+ The reply message(s) will be delivered later to the registered callback.
+ The returned context will help with assigning which call
+ the reply belongs to.
"""
if 'context' not in kwargs:
context = self.get_context()
b = msg.pack(kwargs)
self.transport.write(b)
+ return context
+
+ def read_blocking(self, no_type_conversion=False):
+ """Get next received message from transport within timeout, decoded.
+
+ Note that noticifations have context zero
+ and are not put into receive queue (at least for socket transport),
+ use async_thread with registered callback for processing them.
+
+ If no message appears in the queue within timeout, return None.
+
+ Optionally, type conversion can be skipped,
+ as some of conversions are into less precise types.
+
+ When r is the return value of this, the caller can get message name as:
+ msgname = type(r).__name__
+ and context number (type long) as:
+ context = r.context
+
+ :param no_type_conversion: If false, type conversions are applied.
+ :type no_type_conversion: bool
+ :returns: Decoded message, or None if no message (within timeout).
+ :rtype: Whatever VPPType.unpack returns, depends on no_type_conversion.
+ """
+ msg = self.transport.read()
+ if not msg:
+ return None
+ return self.decode_incoming_msg(msg, no_type_conversion)
def register_event_callback(self, callback):
"""Register a callback for async messages.
if self.event_callback:
self.event_callback(msgname, r)
+ def validate_message_table(self, namecrctable):
+ """Take a dictionary of name_crc message names
+ and returns an array of missing messages"""
+
+ missing_table = []
+ for name_crc in namecrctable:
+ i = self.transport.get_msg_index(name_crc)
+ if i <= 0:
+ missing_table.append(name_crc)
+ return missing_table
+
+ def dump_message_table(self):
+ """Return VPPs API message table as name_crc dictionary"""
+ return self.transport.message_table
+
+ def dump_message_table_filtered(self, msglist):
+ """Return VPPs API message table as name_crc dictionary,
+ filtered by message name list."""
+
+ replies = [self.services[n]['reply'] for n in msglist]
+ message_table_filtered = {}
+ for name in msglist + replies:
+ for k,v in self.transport.message_table.items():
+ if k.startswith(name):
+ message_table_filtered[k] = v
+ break
+ return message_table_filtered
+
def __repr__(self):
return "<VPPApiClient apifiles=%s, testmode=%s, async_thread=%s, " \
"logger=%s, read_timeout=%s, use_socket=%s, " \