diff options
author | Ole Troan <ot@cisco.com> | 2018-11-28 11:36:05 +0100 |
---|---|---|
committer | Neale Ranns <nranns@cisco.com> | 2018-12-13 12:11:50 +0000 |
commit | 413f4a5b2123c1625d615315db293a080078482b (patch) | |
tree | 6cfd8376c1d84b93793b062731ec9594487dc95e | |
parent | 6f666ad99ae1e384aa851af5e0feed3d2a25e709 (diff) |
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>
30 files changed, 349 insertions, 105 deletions
diff --git a/extras/japi/java/jvpp-common/jvpp_common.h b/extras/japi/java/jvpp-common/jvpp_common.h index dd48138a536..e12141b08ba 100644 --- a/extras/japi/java/jvpp-common/jvpp_common.h +++ b/extras/japi/java/jvpp-common/jvpp_common.h @@ -17,6 +17,7 @@ // #include <vppinfra/types.h> #include <vlibapi/api.h> +#include <vlibapi/api_types.h> #include <vlibmemory/api.h> #include <jni.h> diff --git a/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackApiExample.java b/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackApiExample.java index b99979cf301..b6558ffaa7e 100644 --- a/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackApiExample.java +++ b/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackApiExample.java @@ -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); } diff --git a/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackJVppFacadeExample.java b/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackJVppFacadeExample.java index dc2bdcba569..a8b91860b75 100644 --- a/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackJVppFacadeExample.java +++ b/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/CallbackJVppFacadeExample.java @@ -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 diff --git a/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/FutureApiExample.java b/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/FutureApiExample.java index 931c9b337aa..030e68995a2 100644 --- a/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/FutureApiExample.java +++ b/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/FutureApiExample.java @@ -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)); } diff --git a/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/L2AclExample.java b/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/L2AclExample.java index 9a17136a6d9..0be85d4f17f 100644 --- a/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/L2AclExample.java +++ b/extras/japi/java/jvpp-core/io/fd/vpp/jvpp/core/examples/L2AclExample.java @@ -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) { diff --git a/extras/japi/java/jvpp-core/jvpp_core.c b/extras/japi/java/jvpp-core/jvpp_core.c index 09d753026d7..0df8589702c 100644 --- a/extras/japi/java/jvpp-core/jvpp_core.c +++ b/extras/japi/java/jvpp-core/jvpp_core.c @@ -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 { diff --git a/extras/japi/java/jvpp-core/jvpp_core.h b/extras/japi/java/jvpp-core/jvpp_core.h new file mode 100644 index 00000000000..bbf7a71fa31 --- /dev/null +++ b/extras/japi/java/jvpp-core/jvpp_core.h @@ -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; +} diff --git a/extras/japi/java/jvpp/gen/jvppgen/dto_gen.py b/extras/japi/java/jvpp/gen/jvppgen/dto_gen.py index ca015a30456..cbd969d51fe 100755 --- a/extras/japi/java/jvpp/gen/jvppgen/dto_gen.py +++ b/extras/japi/java/jvpp/gen/jvppgen/dto_gen.py @@ -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} + "}"; } diff --git a/extras/japi/java/jvpp/gen/jvppgen/jni_common_gen.py b/extras/japi/java/jvpp/gen/jvppgen/jni_common_gen.py index 708cc1cba81..b52e5ff2d2c 100755 --- a/extras/japi/java/jvpp/gen/jvppgen/jni_common_gen.py +++ b/extras/japi/java/jvpp/gen/jvppgen/jni_common_gen.py @@ -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})); diff --git a/extras/japi/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py b/extras/japi/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py index c5634de2e48..ebc552bfda6 100644 --- a/extras/japi/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py +++ b/extras/japi/java/jvpp/gen/jvppgen/jvpp_callback_facade_gen.py @@ -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); } diff --git a/extras/japi/java/jvpp/gen/jvppgen/jvpp_common_gen.py b/extras/japi/java/jvpp/gen/jvppgen/jvpp_common_gen.py index 83226ea78ac..499adbc3f56 100755 --- a/extras/japi/java/jvpp/gen/jvppgen/jvpp_common_gen.py +++ b/extras/japi/java/jvpp/gen/jvppgen/jvpp_common_gen.py @@ -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 }""") diff --git a/extras/japi/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py b/extras/japi/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py index 47a9985144d..3da367a4d5f 100644 --- a/extras/japi/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py +++ b/extras/japi/java/jvpp/gen/jvppgen/jvpp_future_facade_gen.py @@ -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); } diff --git a/extras/japi/java/jvpp/gen/jvppgen/jvpp_impl_gen.py b/extras/japi/java/jvpp/gen/jvppgen/jvpp_impl_gen.py index aff8d7fc99c..376952b620e 100755 --- a/extras/japi/java/jvpp/gen/jvppgen/jvpp_impl_gen.py +++ b/extras/japi/java/jvpp/gen/jvppgen/jvpp_impl_gen.py @@ -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){ diff --git a/extras/japi/java/jvpp/gen/jvppgen/jvpp_model.py b/extras/japi/java/jvpp/gen/jvppgen/jvpp_model.py index 16099689880..da1e01f5a63 100755 --- a/extras/japi/java/jvpp/gen/jvppgen/jvpp_model.py +++ b/extras/japi/java/jvpp/gen/jvppgen/jvpp_model.py @@ -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(): diff --git a/extras/japi/java/jvpp/gen/jvppgen/notification_gen.py b/extras/japi/java/jvpp/gen/jvppgen/notification_gen.py index 69e870ed33d..fa86fe4bbf2 100644 --- a/extras/japi/java/jvpp/gen/jvppgen/notification_gen.py +++ b/extras/japi/java/jvpp/gen/jvppgen/notification_gen.py @@ -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); } } diff --git a/src/tools/vppapigen/vppapigen_c.py b/src/tools/vppapigen/vppapigen_c.py index f0fb00831c3..e189b024454 100644 --- a/src/tools/vppapigen/vppapigen_c.py +++ b/src/tools/vppapigen/vppapigen_c.py @@ -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) diff --git a/src/tools/vppapigen/vppapigen_json.py b/src/tools/vppapigen/vppapigen_json.py index b57e16c990d..a4707c0cd60 100644 --- a/src/tools/vppapigen/vppapigen_json.py +++ b/src/tools/vppapigen/vppapigen_json.py @@ -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) diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 7f4dabeffa1..25d2dd3112a 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -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); diff --git a/src/vlibapi/CMakeLists.txt b/src/vlibapi/CMakeLists.txt index 55f87b8f7ac..dfd6b5b5045 100644 --- a/src/vlibapi/CMakeLists.txt +++ b/src/vlibapi/CMakeLists.txt @@ -17,6 +17,7 @@ install( api.h vat_helper_macros.h api_common.h + api_types.h DESTINATION include/vlibapi diff --git a/src/vlibapi/api_common.h b/src/vlibapi/api_common.h index 497a1e8bd16..735921b30f7 100644 --- a/src/vlibapi/api_common.h +++ b/src/vlibapi/api_common.h @@ -25,6 +25,7 @@ */ #include <vppinfra/clib_error.h> +#include <vlibapi/api_types.h> #include <svm/svm_common.h> #include <svm/queue.h> diff --git a/src/vlibapi/api_types.h b/src/vlibapi/api_types.h new file mode 100644 index 00000000000..759298e735d --- /dev/null +++ b/src/vlibapi/api_types.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 diff --git a/src/vpp-api/python/vpp_papi/vpp_papi.py b/src/vpp-api/python/vpp_papi/vpp_papi.py index 32abe14da94..4de257c6924 100644 --- a/src/vpp-api/python/vpp_papi/vpp_papi.py +++ b/src/vpp-api/python/vpp_papi/vpp_papi.py @@ -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): diff --git a/src/vpp-api/python/vpp_papi/vpp_serializer.py b/src/vpp-api/python/vpp_papi/vpp_serializer.py index 5dce03b6188..418c0243402 100644 --- a/src/vpp-api/python/vpp_papi/vpp_serializer.py +++ b/src/vpp-api/python/vpp_papi/vpp_serializer.py @@ -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: diff --git a/src/vpp-api/python/vpp_papi/vpp_transport_socket.py b/src/vpp-api/python/vpp_papi/vpp_transport_socket.py index 393e2e9c9c1..4341cad3e90 100644 --- a/src/vpp-api/python/vpp_papi/vpp_transport_socket.py +++ b/src/vpp-api/python/vpp_papi/vpp_transport_socket.py @@ -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) diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index cf5d252e347..1f376dcc64f 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -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* */ } diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index 41a24ef5a34..78d37044955 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -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); diff --git a/src/vpp/api/types.h b/src/vpp/api/types.h index 252caa2d626..9a45639d030 100644 --- a/src/vpp/api/types.h +++ b/src/vpp/api/types.h @@ -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 diff --git a/src/vpp/api/vpe.api b/src/vpp/api/vpe.api index 488af1727bc..24d44bd31e7 100644 --- a/src/vpp/api/vpe.api +++ b/src/vpp/api/vpe.api @@ -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; }; diff --git a/test/framework.py b/test/framework.py index 242a0798212..f82f0750387 100644 --- a/test/framework.py +++ b/test/framework.py @@ -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]) diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 320ea12c6dc..4812cb6ef70 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -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. |