API: Use string type instead of u8.
The new string type is modelled after string in proto3. It is always variable length. Change-Id: I64884067e28a80072c8dac31b7c7c82d6e306051 Signed-off-by: Ole Troan <ot@cisco.com> Signed-off-by: Michal Cmarada <mcmarada@cisco.com> Signed-off-by: Ole Troan <ot@cisco.com>
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
//
|
||||
#include <vppinfra/types.h>
|
||||
#include <vlibapi/api.h>
|
||||
#include <vlibapi/api_types.h>
|
||||
#include <vlibmemory/api.h>
|
||||
#include <jni.h>
|
||||
|
||||
|
||||
@@ -77,17 +77,17 @@ public class CallbackApiExample {
|
||||
System.out.printf("Received ShowVersionReply: context=%d, program=%s, version=%s, "
|
||||
+ "buildDate=%s, buildDirectory=%s%n",
|
||||
msg.context,
|
||||
new String(msg.program, StandardCharsets.UTF_8),
|
||||
new String(msg.version, StandardCharsets.UTF_8),
|
||||
new String(msg.buildDate, StandardCharsets.UTF_8),
|
||||
new String(msg.buildDirectory, StandardCharsets.UTF_8));
|
||||
msg.program,
|
||||
msg.version,
|
||||
msg.buildDate,
|
||||
msg.buildDirectory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwInterfaceDetails(final SwInterfaceDetails msg) {
|
||||
System.out.printf("Received SwInterfaceDetails: interfaceName=%s, l2AddressLength=%d, adminUpDown=%d, "
|
||||
+ "linkUpDown=%d, linkSpeed=%d, linkMtu=%d%n",
|
||||
new String(msg.interfaceName, StandardCharsets.UTF_8), msg.l2AddressLength, msg.adminUpDown,
|
||||
msg.interfaceName, msg.l2AddressLength, msg.adminUpDown,
|
||||
msg.linkUpDown, msg.linkSpeed, (int) msg.linkMtu);
|
||||
}
|
||||
|
||||
|
||||
+8
-8
@@ -39,10 +39,10 @@ public class CallbackJVppFacadeExample {
|
||||
public void onShowVersionReply(final ShowVersionReply msg) {
|
||||
System.out.printf("ShowVersionCallback1 received ShowVersionReply: context=%d, program=%s,"
|
||||
+ "version=%s, buildDate=%s, buildDirectory=%s%n", msg.context,
|
||||
new String(msg.program, StandardCharsets.UTF_8),
|
||||
new String(msg.version, StandardCharsets.UTF_8),
|
||||
new String(msg.buildDate, StandardCharsets.UTF_8),
|
||||
new String(msg.buildDirectory, StandardCharsets.UTF_8));
|
||||
msg.program,
|
||||
msg.version,
|
||||
msg.buildDate,
|
||||
msg.buildDirectory);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -57,10 +57,10 @@ public class CallbackJVppFacadeExample {
|
||||
public void onShowVersionReply(final ShowVersionReply msg) {
|
||||
System.out.printf("ShowVersionCallback2 received ShowVersionReply: context=%d, program=%s,"
|
||||
+ "version=%s, buildDate=%s, buildDirectory=%s%n", msg.context,
|
||||
new String(msg.program, StandardCharsets.UTF_8),
|
||||
new String(msg.version, StandardCharsets.UTF_8),
|
||||
new String(msg.buildDate, StandardCharsets.UTF_8),
|
||||
new String(msg.buildDirectory, StandardCharsets.UTF_8));
|
||||
msg.program,
|
||||
msg.version,
|
||||
msg.buildDate,
|
||||
msg.buildDirectory);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -47,10 +47,10 @@ public class FutureApiExample {
|
||||
LOG.info(
|
||||
String.format(
|
||||
"Received ShowVersionReply: context=%d, program=%s, version=%s, buildDate=%s, buildDirectory=%s%n",
|
||||
reply.context, new String(reply.program, StandardCharsets.UTF_8),
|
||||
new String(reply.version, StandardCharsets.UTF_8),
|
||||
new String(reply.buildDate, StandardCharsets.UTF_8),
|
||||
new String(reply.buildDirectory, StandardCharsets.UTF_8)));
|
||||
reply.context, reply.program,
|
||||
reply.version,
|
||||
reply.buildDate,
|
||||
reply.buildDirectory));
|
||||
}
|
||||
|
||||
private static void testEmptyBridgeDomainDump(final FutureJVppCoreFacade jvpp) throws Exception {
|
||||
@@ -100,7 +100,7 @@ public class FutureApiExample {
|
||||
LOG.info(
|
||||
String.format("Received SwInterfaceDetails: interfaceName=%s, l2AddressLength=%d, adminUpDown=%d, "
|
||||
+ "linkUpDown=%d, linkSpeed=%d, linkMtu=%d%n",
|
||||
new String(details.interfaceName, StandardCharsets.UTF_8),
|
||||
details.interfaceName,
|
||||
details.l2AddressLength, details.adminUpDown,
|
||||
details.linkUpDown, details.linkSpeed, (int) details.linkMtu));
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public class L2AclExample {
|
||||
hexChars[j * 2] = hexArray[v >>> 4];
|
||||
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
|
||||
}
|
||||
return new String(hexChars);
|
||||
return new java.lang.String(hexChars);
|
||||
}
|
||||
|
||||
private static ClassifyTableInfo createClassifyTableInfoRequest(final int tableId) {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
*/
|
||||
|
||||
#include <vnet/vnet.h>
|
||||
|
||||
#include <jvpp-common/jvpp_common.h>
|
||||
#include <vpp/api/vpe_msg_enum.h>
|
||||
#define vl_typedefs /* define message structures */
|
||||
#include <vpp/api/vpe_all_api_h.h>
|
||||
@@ -24,8 +24,7 @@
|
||||
#include <vlibapi/api.h>
|
||||
#include <vlibmemory/api.h>
|
||||
#include <jni.h>
|
||||
|
||||
#include <jvpp-common/jvpp_common.h>
|
||||
#include <jvpp_core.h>
|
||||
|
||||
// TODO: generate jvpp_plugin_name.c files (or at least reuse plugin's main structure)
|
||||
typedef struct {
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Cisco and/or its affiliates.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef VPP_JVPP_CORE_H
|
||||
#define VPP_JVPP_CORE_H
|
||||
|
||||
#include <vlibapi/api_types.h>
|
||||
|
||||
#endif //VPP_JVPP_CORE_H
|
||||
|
||||
// /**
|
||||
// * Host to network byte order conversion for string type. Converts String in Java to VPP string type.
|
||||
// * typedef struct
|
||||
// * {
|
||||
// * u32 length;
|
||||
// * u8 buf[0];
|
||||
// * } __attribute__ ((packed)) vl_api_string_t;
|
||||
// */
|
||||
static void _host_to_net_string(JNIEnv * env, jstring javaString, vl_api_string_t * _net)
|
||||
{
|
||||
const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);
|
||||
int len = strlen(nativeString);
|
||||
|
||||
vl_api_string_t * vl_api_string = (vl_api_string_t *)calloc(1, (sizeof(vl_api_string_t) + len * sizeof(u8)));
|
||||
if (NULL == vl_api_string)
|
||||
return;
|
||||
|
||||
vl_api_string->length = len;
|
||||
memcpy(vl_api_string->buf, nativeString, len);
|
||||
|
||||
_net = vl_api_string;
|
||||
(*env)->ReleaseStringUTFChars(env, javaString, nativeString);
|
||||
}
|
||||
|
||||
//
|
||||
// /**
|
||||
// * Network to host byte order conversion for string type. Converts VPP string type to String in Java
|
||||
// * typedef struct
|
||||
// * {
|
||||
// * u32 length;
|
||||
// * u8 buf[0];
|
||||
// * } __attribute__ ((packed)) vl_api_string_t;
|
||||
// */
|
||||
static jstring _net_to_host_string(JNIEnv * env, const vl_api_string_t * _net)
|
||||
{
|
||||
jstring jstr = (*env)->NewStringUTF(env, (char *)_net->buf);
|
||||
|
||||
return jstr;
|
||||
}
|
||||
@@ -221,7 +221,7 @@ public final class ${details_class}ReplyDump implements io.fd.vpp.jvpp.dto.JVppR
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
public java.lang.String toString() {
|
||||
return "${details_class}ReplyDump{" +
|
||||
"${details_field}=" + ${details_field} + "}";
|
||||
}
|
||||
|
||||
@@ -165,6 +165,7 @@ def _generate_field_length_check(field):
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
||||
# Make sure we do not write more elements that are expected
|
||||
_FIELD_LENGTH_CHECK = Template("""
|
||||
size_t max_size = ${field_length};
|
||||
@@ -177,9 +178,13 @@ def _generate_j2c_scalar_swap(field, struct_ref_name, is_alias):
|
||||
host = field.java_name
|
||||
if not is_alias:
|
||||
net = "%s->%s" % (struct_ref_name, field.name)
|
||||
return " %s;" % field_type.get_host_to_net_function(host, net)
|
||||
if field_type.name == "string":
|
||||
net = "%s->%s" % (struct_ref_name, field.name)
|
||||
return " _host_to_net_%s(env, %s, (vl_api_string_t *) &%s);" % (field_type.name, host, net)
|
||||
else:
|
||||
return " %s;" % field_type.get_host_to_net_function(host, net)
|
||||
else:
|
||||
net = "%s" % (struct_ref_name)
|
||||
net = "%s" % struct_ref_name
|
||||
return " *%s;" % field_type.get_host_to_net_function(host, net)
|
||||
else:
|
||||
return " %s->%s = %s;" % (struct_ref_name, field.name, field.java_name)
|
||||
@@ -424,7 +429,10 @@ _C2J_ENUM_SWAP_TEMPLATE = Template("""
|
||||
def _generate_c2j_primitive_type_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias):
|
||||
field_type = field.type
|
||||
if not is_alias:
|
||||
template = _C2J_PRIMITIVE_TYPE_SWAP_TEMPLATE
|
||||
if field_type.name == "string":
|
||||
template = _C2J_STRING_TYPE_SWAP_TEMPLATE
|
||||
else:
|
||||
template = _C2J_PRIMITIVE_TYPE_SWAP_TEMPLATE
|
||||
else:
|
||||
template = _C2J_ALIAS_PRIMITIVE_TYPE_SWAP_TEMPLATE
|
||||
return template.substitute(
|
||||
@@ -444,6 +452,12 @@ _C2J_PRIMITIVE_TYPE_SWAP_TEMPLATE = Template("""
|
||||
""")
|
||||
|
||||
|
||||
_C2J_STRING_TYPE_SWAP_TEMPLATE = Template("""
|
||||
jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
|
||||
(*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${net_to_host_function}(env, (const vl_api_string_t *) &${struct_ref_name}->${c_name}));
|
||||
""")
|
||||
|
||||
|
||||
_C2J_ALIAS_PRIMITIVE_TYPE_SWAP_TEMPLATE = Template("""
|
||||
jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
|
||||
(*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${net_to_host_function}(*${struct_ref_name}));
|
||||
|
||||
@@ -210,7 +210,7 @@ public final class CallbackJVpp${plugin_name}FacadeCallback implements $plugin_p
|
||||
failedCall.onError(reply);
|
||||
} catch(RuntimeException ex) {
|
||||
ex.addSuppressed(reply);
|
||||
LOG.log(java.util.logging.Level.WARNING, String.format("Callback: %s failed while handling exception: %s", failedCall, reply), ex);
|
||||
LOG.log(java.util.logging.Level.WARNING, java.lang.String.format("Callback: %s failed while handling exception: %s", failedCall, reply), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -265,7 +265,7 @@ _CALLBACK_METHOD_TEMPLATE = Template("""
|
||||
$plugin_package.callback.$callback callback;
|
||||
final int replyId = reply.context;
|
||||
if (LOG.isLoggable(java.util.logging.Level.FINE)) {
|
||||
LOG.fine(String.format("Received ${message} event message: %s", reply));
|
||||
LOG.fine(java.lang.String.format("Received ${message} event message: %s", reply));
|
||||
}
|
||||
synchronized(requests) {
|
||||
callback = ($plugin_package.callback.$callback) requests.remove(replyId);
|
||||
@@ -282,7 +282,7 @@ _CALLBACK_EVENT_METHOD_TEMPLATE = Template("""
|
||||
@SuppressWarnings("unchecked")
|
||||
public void on${message}($plugin_package.dto.${message} notification) {
|
||||
if (LOG.isLoggable(java.util.logging.Level.FINE)) {
|
||||
LOG.fine(String.format("Received ${message} event message: %s", notification));
|
||||
LOG.fine(java.lang.String.format("Received ${message} event message: %s", notification));
|
||||
}
|
||||
eventCallback.on${message}(notification);
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ def generate_to_string(class_name, fields):
|
||||
|
||||
_TO_STRING_TEMPLATE = Template("""
|
||||
@Override
|
||||
public String toString() {
|
||||
public java.lang.String toString() {
|
||||
return "$class_name{" +
|
||||
$to_string_fields
|
||||
}""")
|
||||
|
||||
@@ -280,7 +280,7 @@ _FUTURE_JVPP_FACADE_DETAILS_CALLBACK_TEMPLATE = Template("""
|
||||
io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.dto.${callback_dto}ReplyDump> completableFuture;
|
||||
final int replyId = reply.context;
|
||||
if (LOG.isLoggable(java.util.logging.Level.FINE)) {
|
||||
LOG.fine(String.format("Received $callback_dto event message: %s", reply));
|
||||
LOG.fine(java.lang.String.format("Received $callback_dto event message: %s", reply));
|
||||
}
|
||||
synchronized(requests) {
|
||||
completableFuture = (io.fd.vpp.jvpp.future.AbstractFutureJVppInvoker.CompletableDumpFuture<$plugin_package.dto.${callback_dto}ReplyDump>) requests.get(replyId);
|
||||
@@ -305,7 +305,7 @@ _FUTURE_JVPP_FACADE_REPLY_CALLBACK_TEMPLATE = Template("""
|
||||
java.util.concurrent.CompletableFuture<io.fd.vpp.jvpp.dto.JVppReply<$plugin_package.dto.$request_dto>> completableFuture;
|
||||
final int replyId = reply.context;
|
||||
if (LOG.isLoggable(java.util.logging.Level.FINE)) {
|
||||
LOG.fine(String.format("Received $callback_dto event message: %s", reply));
|
||||
LOG.fine(java.lang.String.format("Received $callback_dto event message: %s", reply));
|
||||
}
|
||||
synchronized(requests) {
|
||||
completableFuture =
|
||||
@@ -331,7 +331,7 @@ _FUTURE_JVPP_FACADE_EVENT_CALLBACK_TEMPLATE = Template("""
|
||||
@Override
|
||||
public void on$callback_dto($plugin_package.dto.$callback_dto notification) {
|
||||
if (LOG.isLoggable(java.util.logging.Level.FINE)) {
|
||||
LOG.fine(String.format("Received $callback_dto event message: %s", notification));
|
||||
LOG.fine(java.lang.String.format("Received $callback_dto event message: %s", notification));
|
||||
}
|
||||
notificationCallback.on$callback_dto(notification);
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ import io.fd.vpp.jvpp.JVppRegistry;
|
||||
public final class JVpp${plugin_name}Impl implements $plugin_package.JVpp${plugin_name} {
|
||||
|
||||
private final static Logger LOG = Logger.getLogger(JVpp${plugin_name}Impl.class.getName());
|
||||
private static final String LIBNAME = "libjvpp_${plugin_name_underscore}.so";
|
||||
private static final java.lang.String LIBNAME = "libjvpp_${plugin_name_underscore}.so";
|
||||
|
||||
// FIXME using NativeLibraryLoader makes load fail could not find (WantInterfaceEventsReply).
|
||||
static {
|
||||
@@ -151,7 +151,7 @@ _JVPP_IMPL_METHOD_TEMPLATE = Template("""
|
||||
java.util.Objects.requireNonNull(request, "Null request object");
|
||||
connection.checkActive();
|
||||
if (LOG.isLoggable(Level.FINE)) {
|
||||
LOG.fine(String.format("Sending $type event message: %s", request));
|
||||
LOG.fine(java.lang.String.format("Sending $type event message: %s", request));
|
||||
}
|
||||
int result=${name}0(request);
|
||||
if (result<0){
|
||||
|
||||
@@ -92,9 +92,11 @@ class SimpleType(Type):
|
||||
|
||||
# TODO(VPP-1187): add array host to net functions to reduce number of members and simplify JNI generation
|
||||
class Array(Type):
|
||||
def __init__(self, base_type):
|
||||
def __init__(self, base_type, name=None):
|
||||
if name is None:
|
||||
name = base_type.name + _ARRAY_SUFFIX
|
||||
super(Array, self).__init__(
|
||||
name=base_type.name + _ARRAY_SUFFIX,
|
||||
name=name,
|
||||
java_name=base_type.java_name + _ARRAY_SUFFIX,
|
||||
java_name_fqn=base_type.java_name_fqn + _ARRAY_SUFFIX,
|
||||
jni_signature="[%s" % base_type.jni_signature,
|
||||
@@ -341,6 +343,8 @@ class JVppModel(object):
|
||||
self._parse_types(types)
|
||||
|
||||
def _parse_aliases(self, types):
|
||||
|
||||
# model aliases
|
||||
for alias_name in self._aliases:
|
||||
alias = self._aliases[alias_name]
|
||||
alias_type = {"type": "type"}
|
||||
@@ -442,7 +446,10 @@ class JVppModel(object):
|
||||
'i64': SimpleType('i64', 'long', 'J', 'jlong', 'Long',
|
||||
host_to_net_function='clib_host_to_net_i64',
|
||||
net_to_host_function='clib_net_to_host_i64'),
|
||||
'f64': SimpleType('f64', 'double', 'D', 'jdouble', 'Double')
|
||||
'f64': SimpleType('f64', 'double', 'D', 'jdouble', 'Double'),
|
||||
'string': SimpleType('string', 'String', 'l', 'jstring', 'Object',
|
||||
host_to_net_function='_host_to_net_string',
|
||||
net_to_host_function='_net_to_host_string')
|
||||
})
|
||||
|
||||
for n, t in self._types_by_name.items():
|
||||
|
||||
@@ -117,7 +117,7 @@ _HANDLER_IMPL_TEMPLATE = Template("""
|
||||
public void on$notification(
|
||||
final $plugin_package.dto.$notification notification) {
|
||||
if (LOG.isLoggable(java.util.logging.Level.FINE)) {
|
||||
LOG.fine(String.format("Received $notification event message: %s", notification));
|
||||
LOG.fine(java.lang.String.format("Received $notification event message: %s", notification));
|
||||
}
|
||||
final io.fd.vpp.jvpp.callback.JVppCallback jVppCallback = registeredCallbacks.get($plugin_package.dto.$notification.class);
|
||||
if (null != jVppCallback) {
|
||||
@@ -153,7 +153,7 @@ public final class ${plugin_name}EventRegistryImpl implements ${plugin_name}Even
|
||||
@Override
|
||||
public void onError(io.fd.vpp.jvpp.VppCallbackException ex) {
|
||||
java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(${plugin_name}EventRegistryImpl.class.getName());
|
||||
LOG.log(java.util.logging.Level.WARNING, String.format("Received onError exception: call=%s, context=%d, retval=%d%n", ex.getMethodName(),
|
||||
LOG.log(java.util.logging.Level.WARNING, java.lang.String.format("Received onError exception: call=%s, context=%d, retval=%d%n", ex.getMethodName(),
|
||||
ex.getCtxId(), ex.getErrorCode()), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ import datetime
|
||||
import os
|
||||
import time
|
||||
|
||||
datestring = datetime.datetime.utcfromtimestamp(int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))
|
||||
datestring = datetime.datetime.utcfromtimestamp(
|
||||
int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))
|
||||
input_filename = 'inputfil'
|
||||
top_boilerplate = '''\
|
||||
/*
|
||||
@@ -94,6 +95,13 @@ def duplicate_wrapper_tail():
|
||||
return '#endif\n\n'
|
||||
|
||||
|
||||
def api2c(fieldtype):
|
||||
mappingtable = {'string': 'vl_api_string_t', }
|
||||
if fieldtype in mappingtable:
|
||||
return mappingtable[fieldtype]
|
||||
return fieldtype
|
||||
|
||||
|
||||
def typedefs(objs, aliases, filename):
|
||||
name = filename.replace('.', '_')
|
||||
output = '''\
|
||||
@@ -130,12 +138,12 @@ def typedefs(objs, aliases, filename):
|
||||
output += "typedef VL_API_PACKED(struct _vl_api_%s {\n" % o.name
|
||||
for b in o.block:
|
||||
if b.type == 'Field':
|
||||
output += " %s %s;\n" % (b.fieldtype, b.fieldname)
|
||||
output += " %s %s;\n" % (api2c(b.fieldtype), b.fieldname)
|
||||
elif b.type == 'Array':
|
||||
if b.lengthfield:
|
||||
output += " %s %s[0];\n" % (b.fieldtype, b.fieldname)
|
||||
output += " %s %s[0];\n" % (api2c(b.fieldtype), b.fieldname)
|
||||
else:
|
||||
output += " %s %s[%s];\n" % (b.fieldtype, b.fieldname,
|
||||
output += " %s %s[%s];\n" % (api2c(b.fieldtype), b.fieldname,
|
||||
b.length)
|
||||
else:
|
||||
raise ValueError("Error in processing array type %s" % b)
|
||||
|
||||
@@ -32,19 +32,18 @@ def walk_defs(s):
|
||||
d = []
|
||||
d.append(t.name)
|
||||
for b in t.block:
|
||||
f = []
|
||||
if b.type == 'Field':
|
||||
f = [b.fieldtype, b.fieldname]
|
||||
d.append([b.fieldtype, b.fieldname])
|
||||
elif b.type == 'Array':
|
||||
if b.lengthfield:
|
||||
f = [b.fieldtype, b.fieldname, b.length, b.lengthfield]
|
||||
d.append([b.fieldtype, b.fieldname, b.length, b.lengthfield])
|
||||
else:
|
||||
f = [b.fieldtype, b.fieldname, b.length]
|
||||
d.append([b.fieldtype, b.fieldname, b.length])
|
||||
elif b.type == 'Union':
|
||||
print('UNION')
|
||||
pass
|
||||
else:
|
||||
raise ValueError("Error in processing array type %s" % b)
|
||||
d.append(f)
|
||||
|
||||
if t.crc:
|
||||
c = {}
|
||||
c['crc'] = "{0:#0{1}x}".format(t.crc, 10)
|
||||
|
||||
+33
-13
@@ -1105,7 +1105,7 @@ vl_api_cli_inband_reply_t_handler (vl_api_cli_inband_reply_t * mp)
|
||||
{
|
||||
vat_main_t *vam = &vat_main;
|
||||
i32 retval = ntohl (mp->retval);
|
||||
u32 length = ntohl (mp->length);
|
||||
u32 length = vl_api_string_len (&mp->reply);
|
||||
|
||||
vec_reset_length (vam->cmd_reply);
|
||||
|
||||
@@ -1113,7 +1113,8 @@ vl_api_cli_inband_reply_t_handler (vl_api_cli_inband_reply_t * mp)
|
||||
if (retval == 0)
|
||||
{
|
||||
vec_validate (vam->cmd_reply, length);
|
||||
clib_memcpy ((char *) (vam->cmd_reply), mp->reply, length);
|
||||
clib_memcpy ((char *) (vam->cmd_reply),
|
||||
vl_api_from_api_string (&mp->reply), length);
|
||||
vam->cmd_reply[length] = 0;
|
||||
}
|
||||
vam->result_ready = 1;
|
||||
@@ -1129,7 +1130,8 @@ vl_api_cli_inband_reply_t_handler_json (vl_api_cli_inband_reply_t * mp)
|
||||
|
||||
vat_json_init_object (&node);
|
||||
vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
|
||||
vat_json_object_add_string_copy (&node, "reply", mp->reply);
|
||||
vat_json_object_add_string_copy (&node, "reply",
|
||||
vl_api_from_api_string (&mp->reply));
|
||||
|
||||
vat_json_print (vam->ofp, &node);
|
||||
vat_json_free (&node);
|
||||
@@ -1300,10 +1302,18 @@ static void vl_api_show_version_reply_t_handler
|
||||
|
||||
if (retval >= 0)
|
||||
{
|
||||
errmsg (" program: %s", mp->program);
|
||||
errmsg (" version: %s", mp->version);
|
||||
errmsg (" build date: %s", mp->build_date);
|
||||
errmsg ("build directory: %s", mp->build_directory);
|
||||
char *p = (char *) &mp->program;
|
||||
errmsg (" program: %s\n",
|
||||
vl_api_from_api_string ((vl_api_string_t *) p));
|
||||
p += vl_api_string_len ((vl_api_string_t *) p) + sizeof (u32);
|
||||
errmsg (" version: %s\n",
|
||||
vl_api_from_api_string ((vl_api_string_t *) p));
|
||||
p += vl_api_string_len ((vl_api_string_t *) p) + sizeof (u32);
|
||||
errmsg (" build date: %s\n",
|
||||
vl_api_from_api_string ((vl_api_string_t *) p));
|
||||
p += vl_api_string_len ((vl_api_string_t *) p) + sizeof (u32);
|
||||
errmsg ("build directory: %s\n",
|
||||
vl_api_from_api_string ((vl_api_string_t *) p));
|
||||
}
|
||||
vam->retval = retval;
|
||||
vam->result_ready = 1;
|
||||
@@ -1317,11 +1327,22 @@ static void vl_api_show_version_reply_t_handler_json
|
||||
|
||||
vat_json_init_object (&node);
|
||||
vat_json_object_add_int (&node, "retval", ntohl (mp->retval));
|
||||
vat_json_object_add_string_copy (&node, "program", mp->program);
|
||||
vat_json_object_add_string_copy (&node, "version", mp->version);
|
||||
vat_json_object_add_string_copy (&node, "build_date", mp->build_date);
|
||||
char *p = (char *) &mp->program;
|
||||
vat_json_object_add_string_copy (&node, "program",
|
||||
vl_api_from_api_string ((vl_api_string_t *)
|
||||
p));
|
||||
p += vl_api_string_len ((vl_api_string_t *) p) + sizeof (u32);
|
||||
vat_json_object_add_string_copy (&node, "version",
|
||||
vl_api_from_api_string ((vl_api_string_t *)
|
||||
p));
|
||||
p += vl_api_string_len ((vl_api_string_t *) p) + sizeof (u32);
|
||||
vat_json_object_add_string_copy (&node, "build_date",
|
||||
vl_api_from_api_string ((vl_api_string_t *)
|
||||
p));
|
||||
p += vl_api_string_len ((vl_api_string_t *) p) + sizeof (u32);
|
||||
vat_json_object_add_string_copy (&node, "build_directory",
|
||||
mp->build_directory);
|
||||
vl_api_from_api_string ((vl_api_string_t *)
|
||||
p));
|
||||
|
||||
vat_json_print (vam->ofp, &node);
|
||||
vat_json_free (&node);
|
||||
@@ -6339,8 +6360,7 @@ exec_inband (vat_main_t * vam)
|
||||
*/
|
||||
u32 len = vec_len (vam->input->buffer);
|
||||
M2 (CLI_INBAND, mp, len);
|
||||
clib_memcpy (mp->cmd, vam->input->buffer, len);
|
||||
mp->length = htonl (len);
|
||||
vl_api_to_api_string (len, (const char *) vam->input->buffer, &mp->cmd);
|
||||
|
||||
S (mp);
|
||||
W (ret);
|
||||
|
||||
@@ -17,6 +17,7 @@ install(
|
||||
api.h
|
||||
vat_helper_macros.h
|
||||
api_common.h
|
||||
api_types.h
|
||||
|
||||
DESTINATION
|
||||
include/vlibapi
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
#include <vppinfra/clib_error.h>
|
||||
#include <vlibapi/api_types.h>
|
||||
#include <svm/svm_common.h>
|
||||
#include <svm/queue.h>
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
*------------------------------------------------------------------
|
||||
* api_types.h
|
||||
*
|
||||
* Copyright (c) 2018 Cisco and/or its affiliates.
|
||||
* 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.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef included_api_types_h
|
||||
#define included_api_types_h
|
||||
|
||||
#include <vppinfra/types.h>
|
||||
|
||||
/* VPP API string type */
|
||||
typedef struct
|
||||
{
|
||||
u32 length;
|
||||
u8 buf[0];
|
||||
} __attribute__ ((packed)) vl_api_string_t;
|
||||
|
||||
static inline int
|
||||
vl_api_to_api_string (u32 len, const char *buf, vl_api_string_t * str)
|
||||
{
|
||||
if (strncpy_s ((char *) str->buf, len, buf, len - 1) != 0)
|
||||
len = 0;
|
||||
str->length = clib_host_to_net_u32 (len);
|
||||
return len + sizeof (u32);
|
||||
}
|
||||
|
||||
/* Return a C string from API string */
|
||||
static inline u8 *
|
||||
vl_api_from_api_string (vl_api_string_t * astr)
|
||||
{
|
||||
return astr->buf;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
vl_api_string_len (vl_api_string_t * astr)
|
||||
{
|
||||
return clib_net_to_host_u32 (astr->length);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -29,6 +29,8 @@ import atexit
|
||||
from . vpp_serializer import VPPType, VPPEnumType, VPPUnionType, BaseTypes
|
||||
from . vpp_serializer import VPPMessage, vpp_get_type, VPPTypeAlias
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
if sys.version[0] == '2':
|
||||
import Queue as queue
|
||||
else:
|
||||
@@ -63,6 +65,19 @@ else:
|
||||
return d.items()
|
||||
|
||||
|
||||
def call_logger(msgdef, kwargs):
|
||||
s = 'Calling {}('.format(msgdef.name)
|
||||
for k, v in kwargs.items():
|
||||
s += '{}:{} '.format(k, v)
|
||||
s += ')'
|
||||
return s
|
||||
|
||||
|
||||
def return_logger(r):
|
||||
s = 'Return from {}'.format(r)
|
||||
return s
|
||||
|
||||
|
||||
class VppApiDynamicMethodHolder(object):
|
||||
pass
|
||||
|
||||
@@ -493,10 +508,31 @@ class VPP(object):
|
||||
else:
|
||||
raise VPPIOError(2, 'RPC reply message received in event handler')
|
||||
|
||||
def has_context(self, msg):
|
||||
if len(msg) < 10:
|
||||
return False
|
||||
|
||||
header = VPPType('header_with_context', [['u16', 'msgid'],
|
||||
['u32', 'client_index'],
|
||||
['u32', 'context']])
|
||||
|
||||
(i, ci, context), size = header.unpack(msg, 0)
|
||||
if self.id_names[i] == 'rx_thread_exit':
|
||||
return
|
||||
|
||||
#
|
||||
# Decode message and returns a tuple.
|
||||
#
|
||||
msgobj = self.id_msgdef[i]
|
||||
if 'context' in msgobj.field_by_name and context >= 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
def decode_incoming_msg(self, msg, no_type_conversion=False):
|
||||
if not msg:
|
||||
self.logger.warning('vpp_api.read failed')
|
||||
return
|
||||
|
||||
(i, ci), size = self.header.unpack(msg, 0)
|
||||
if self.id_names[i] == 'rx_thread_exit':
|
||||
return
|
||||
@@ -537,7 +573,7 @@ class VPP(object):
|
||||
raise VPPValueError('Invalid argument {} to {}'
|
||||
.format(list(d), msg.name))
|
||||
|
||||
def _call_vpp(self, i, msg, multipart, **kwargs):
|
||||
def _call_vpp(self, i, msgdef, multipart, **kwargs):
|
||||
"""Given a message, send the message and await a reply.
|
||||
|
||||
msgdef - the message packing definition
|
||||
@@ -567,8 +603,11 @@ class VPP(object):
|
||||
kwargs['client_index'] = self.transport.socket_index
|
||||
except AttributeError:
|
||||
pass
|
||||
self.validate_args(msg, kwargs)
|
||||
b = msg.pack(kwargs)
|
||||
self.validate_args(msgdef, kwargs)
|
||||
|
||||
logging.debug(call_logger(msgdef, kwargs))
|
||||
|
||||
b = msgdef.pack(kwargs)
|
||||
self.transport.suspend()
|
||||
|
||||
self.transport.write(b)
|
||||
@@ -601,6 +640,7 @@ class VPP(object):
|
||||
|
||||
self.transport.resume()
|
||||
|
||||
logger.debug(return_logger(rl))
|
||||
return rl
|
||||
|
||||
def _call_vpp_async(self, i, msg, **kwargs):
|
||||
|
||||
@@ -59,6 +59,7 @@ def conversion_unpacker(data, field_type):
|
||||
class BaseTypes(object):
|
||||
def __init__(self, type, elements=0):
|
||||
base_types = {'u8': '>B',
|
||||
'string': '>s',
|
||||
'u16': '>H',
|
||||
'u32': '>I',
|
||||
'i32': '>i',
|
||||
@@ -67,13 +68,11 @@ class BaseTypes(object):
|
||||
'bool': '>?',
|
||||
'header': '>HI'}
|
||||
|
||||
if elements > 0 and type == 'u8':
|
||||
if elements > 0 and (type == 'u8' or type == 'string'):
|
||||
self.packer = struct.Struct('>%ss' % elements)
|
||||
else:
|
||||
self.packer = struct.Struct(base_types[type])
|
||||
self.size = self.packer.size
|
||||
logger.debug('Adding {} with format: {}'
|
||||
.format(type, base_types[type]))
|
||||
|
||||
def pack(self, data, kwargs=None):
|
||||
if not data: # Default to zero if not specified
|
||||
@@ -84,10 +83,32 @@ class BaseTypes(object):
|
||||
return self.packer.unpack_from(data, offset)[0], self.packer.size
|
||||
|
||||
|
||||
class String(object):
|
||||
def __init__(self):
|
||||
self.name = 'string'
|
||||
self.size = 1
|
||||
self.length_field_packer = BaseTypes('u32')
|
||||
|
||||
def pack(self, list, kwargs=None):
|
||||
if not list:
|
||||
return self.length_field_packer.pack(0) + b""
|
||||
return self.length_field_packer.pack(len(list)) + list.encode('utf8')
|
||||
|
||||
def unpack(self, data, offset=0, result=None, ntc=False):
|
||||
length, length_field_size = self.length_field_packer.unpack(data,
|
||||
offset)
|
||||
if length == 0:
|
||||
return b'', 0
|
||||
p = BaseTypes('u8', length)
|
||||
x, size = p.unpack(data, offset + length_field_size)
|
||||
x2 = x.split(b'\0',1)[0]
|
||||
return (x2.decode('utf8'), size + length_field_size)
|
||||
|
||||
|
||||
types = {'u8': BaseTypes('u8'), 'u16': BaseTypes('u16'),
|
||||
'u32': BaseTypes('u32'), 'i32': BaseTypes('i32'),
|
||||
'u64': BaseTypes('u64'), 'f64': BaseTypes('f64'),
|
||||
'bool': BaseTypes('bool')}
|
||||
'bool': BaseTypes('bool'), 'string': String()}
|
||||
|
||||
|
||||
def vpp_get_type(name):
|
||||
@@ -107,6 +128,7 @@ class FixedList_u8(object):
|
||||
self.num = num
|
||||
self.packer = BaseTypes(field_type, num)
|
||||
self.size = self.packer.size
|
||||
self.field_type = field_type
|
||||
|
||||
def pack(self, data, kwargs=None):
|
||||
"""Packs a fixed length bytestring. Left-pads with zeros
|
||||
@@ -128,6 +150,10 @@ class FixedList_u8(object):
|
||||
'Invalid array length for "{}" got {}'
|
||||
' expected {}'
|
||||
.format(self.name, len(data[offset:]), self.num))
|
||||
if self.field_type == 'string':
|
||||
s = self.packer.unpack(data, offset)
|
||||
s2 = s[0].split(b'\0', 1)[0]
|
||||
return (s2.decode('utf-8'), self.num)
|
||||
return self.packer.unpack(data, offset)
|
||||
|
||||
|
||||
@@ -164,6 +190,7 @@ class FixedList(object):
|
||||
class VLAList(object):
|
||||
def __init__(self, name, field_type, len_field_name, index):
|
||||
self.name = name
|
||||
self.field_type = field_type
|
||||
self.index = index
|
||||
self.packer = types[field_type]
|
||||
self.size = self.packer.size
|
||||
@@ -179,6 +206,7 @@ class VLAList(object):
|
||||
b = bytes()
|
||||
|
||||
# u8 array
|
||||
|
||||
if self.packer.size == 1:
|
||||
return bytearray(list)
|
||||
|
||||
@@ -249,7 +277,6 @@ class VPPEnumType(object):
|
||||
e_hash[ename] = evalue
|
||||
self.enum = IntEnum(name, e_hash)
|
||||
types[name] = self
|
||||
logger.debug('Adding enum {}'.format(name))
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self.enum[name]
|
||||
@@ -290,7 +317,6 @@ class VPPUnionType(object):
|
||||
|
||||
types[name] = self
|
||||
self.tuple = collections.namedtuple(name, fields, rename=True)
|
||||
logger.debug('Adding union {}'.format(name))
|
||||
|
||||
# Union of variable length?
|
||||
def pack(self, data, kwargs=None):
|
||||
@@ -381,7 +407,7 @@ class VPPType(object):
|
||||
if list_elements == 0:
|
||||
p = VLAList_legacy(f_name, f_type)
|
||||
self.packers.append(p)
|
||||
elif f_type == 'u8':
|
||||
elif f_type == 'u8' or f_type == 'string':
|
||||
p = FixedList_u8(f_name, f_type, list_elements)
|
||||
self.packers.append(p)
|
||||
size += p.size
|
||||
@@ -390,10 +416,9 @@ class VPPType(object):
|
||||
self.packers.append(p)
|
||||
size += p.size
|
||||
elif len(f) == 4: # Variable length list
|
||||
# Find index of length field
|
||||
length_index = self.fields.index(f[3])
|
||||
p = VLAList(f_name, f_type, f[3], length_index)
|
||||
self.packers.append(p)
|
||||
length_index = self.fields.index(f[3])
|
||||
p = VLAList(f_name, f_type, f[3], length_index)
|
||||
self.packers.append(p)
|
||||
else:
|
||||
self.packers.append(types[f_type])
|
||||
size += types[f_type].size
|
||||
@@ -401,7 +426,6 @@ class VPPType(object):
|
||||
self.size = size
|
||||
self.tuple = collections.namedtuple(name, self.fields, rename=True)
|
||||
types[name] = self
|
||||
logger.debug('Adding type {}'.format(name))
|
||||
|
||||
def pack(self, data, kwargs=None):
|
||||
if not kwargs:
|
||||
|
||||
@@ -59,8 +59,7 @@ class VppTransport(object):
|
||||
return
|
||||
# Put either to local queue or if context == 0
|
||||
# callback queue
|
||||
r = self.parent.decode_incoming_msg(msg)
|
||||
if hasattr(r, 'context') and r.context > 0:
|
||||
if self.parent.has_context(msg):
|
||||
self.q.put(msg)
|
||||
else:
|
||||
self.parent.msg_handler_async(msg)
|
||||
|
||||
+27
-12
@@ -217,16 +217,25 @@ vl_api_cli_inband_t_handler (vl_api_cli_inband_t * mp)
|
||||
vlib_main_t *vm = vlib_get_main ();
|
||||
unformat_input_t input;
|
||||
u8 *out_vec = 0;
|
||||
u32 len = 0;
|
||||
|
||||
unformat_init_string (&input, (char *) mp->cmd, ntohl (mp->length));
|
||||
if (vl_msg_api_get_msg_length (mp) < vl_api_string_len (&mp->cmd))
|
||||
{
|
||||
rv = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
unformat_init_string (&input, (char *) vl_api_from_api_string (&mp->cmd),
|
||||
vl_api_string_len (&mp->cmd));
|
||||
vlib_cli_input (vm, &input, inband_cli_output, (uword) & out_vec);
|
||||
|
||||
u32 len = vec_len (out_vec);
|
||||
len = vec_len (out_vec);
|
||||
|
||||
error:
|
||||
/* *INDENT-OFF* */
|
||||
REPLY_MACRO3(VL_API_CLI_INBAND_REPLY, len,
|
||||
({
|
||||
rmp->length = htonl (len);
|
||||
clib_memcpy (rmp->reply, out_vec, len);
|
||||
vl_api_to_api_string(len, (const char *)out_vec, &rmp->reply);
|
||||
}));
|
||||
/* *INDENT-ON* */
|
||||
vec_free (out_vec);
|
||||
@@ -241,16 +250,22 @@ vl_api_show_version_t_handler (vl_api_show_version_t * mp)
|
||||
char *vpe_api_get_version (void);
|
||||
char *vpe_api_get_build_date (void);
|
||||
|
||||
u32 program_len = strnlen_s ("vpe", 32) + 1;
|
||||
u32 version_len = strnlen_s (vpe_api_get_version (), 32) + 1;
|
||||
u32 build_date_len = strnlen_s (vpe_api_get_build_date (), 32) + 1;
|
||||
u32 build_directory_len =
|
||||
strnlen_s (vpe_api_get_build_directory (), 256) + 1;
|
||||
|
||||
u32 n = program_len + version_len + build_date_len + build_directory_len;
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
REPLY_MACRO2(VL_API_SHOW_VERSION_REPLY,
|
||||
REPLY_MACRO3(VL_API_SHOW_VERSION_REPLY, n,
|
||||
({
|
||||
strncpy ((char *) rmp->program, "vpe", ARRAY_LEN(rmp->program)-1);
|
||||
strncpy ((char *) rmp->build_directory, vpe_api_get_build_directory(),
|
||||
ARRAY_LEN(rmp->build_directory)-1);
|
||||
strncpy ((char *) rmp->version, vpe_api_get_version(),
|
||||
ARRAY_LEN(rmp->version)-1);
|
||||
strncpy ((char *) rmp->build_date, vpe_api_get_build_date(),
|
||||
ARRAY_LEN(rmp->build_date)-1);
|
||||
char *p = (char *)&rmp->program;
|
||||
p += vl_api_to_api_string(program_len, "vpe", (vl_api_string_t *)p);
|
||||
p += vl_api_to_api_string(version_len, vpe_api_get_version(), (vl_api_string_t *)p);
|
||||
p += vl_api_to_api_string(build_date_len, vpe_api_get_build_date(), (vl_api_string_t *)p);
|
||||
vl_api_to_api_string(build_directory_len, vpe_api_get_build_directory(), (vl_api_string_t *)p);
|
||||
}));
|
||||
/* *INDENT-ON* */
|
||||
}
|
||||
|
||||
@@ -2109,10 +2109,10 @@ static void *vl_api_cli_inband_t_print
|
||||
{
|
||||
u8 *s;
|
||||
u8 *cmd = 0;
|
||||
u32 length = ntohl (mp->length);
|
||||
u32 length = vl_api_string_len (&mp->cmd);
|
||||
|
||||
vec_validate (cmd, length);
|
||||
clib_memcpy (cmd, mp->cmd, length);
|
||||
clib_memcpy (cmd, vl_api_from_api_string (&mp->cmd), length);
|
||||
|
||||
s = format (0, "SCRIPT: exec %v ", cmd);
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#ifndef __API_TYPES_H__
|
||||
#define __API_TYPES_H__
|
||||
|
||||
#include <vlibapi/api_common.h>
|
||||
#include <vlibapi/api_types.h>
|
||||
|
||||
#define vl_typedefs /* define message structures */
|
||||
#include <vpp/api/vpe_all_api_h.h>
|
||||
#undef vl_typedefs
|
||||
|
||||
+6
-8
@@ -93,8 +93,7 @@ define cli_inband
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 length;
|
||||
u8 cmd[length];
|
||||
string cmd;
|
||||
};
|
||||
|
||||
/** \brief vpe parser cli string response
|
||||
@@ -112,8 +111,7 @@ define cli_inband_reply
|
||||
{
|
||||
u32 context;
|
||||
i32 retval;
|
||||
u32 length;
|
||||
u8 reply[length];
|
||||
string reply;
|
||||
};
|
||||
|
||||
/** \brief Get node index using name request
|
||||
@@ -187,10 +185,10 @@ define show_version_reply
|
||||
{
|
||||
u32 context;
|
||||
i32 retval;
|
||||
u8 program[32];
|
||||
u8 version[32];
|
||||
u8 build_date[32];
|
||||
u8 build_directory[256];
|
||||
string program;
|
||||
string version;
|
||||
string build_date;
|
||||
string build_directory;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -918,7 +918,7 @@ class VppTestCase(unittest.TestCase):
|
||||
def assert_packet_counter_equal(self, counter, expected_value):
|
||||
counters = self.vapi.cli("sh errors").split('\n')
|
||||
counter_value = -1
|
||||
for i in range(1, len(counters) - 1):
|
||||
for i in range(1, len(counters)):
|
||||
results = counters[i].split()
|
||||
if results[1] == counter:
|
||||
counter_value = int(results[0])
|
||||
|
||||
@@ -210,10 +210,10 @@ class VppPapiProvider(object):
|
||||
"""
|
||||
self.hook.before_cli(cli)
|
||||
cli += '\n'
|
||||
r = self.papi.cli_inband(length=len(cli), cmd=str(cli).encode('utf8'))
|
||||
r = self.papi.cli_inband(cmd=cli)
|
||||
self.hook.after_cli(cli)
|
||||
if hasattr(r, 'reply'):
|
||||
return r.reply.decode().rstrip('\x00')
|
||||
return r.reply
|
||||
|
||||
def ppcli(self, cli):
|
||||
""" Helper method to print CLI command in case of info logging level.
|
||||
|
||||
Reference in New Issue
Block a user