From 205c75c8dbb81e8629d514a9d407a9f82d0c90e7 Mon Sep 17 00:00:00 2001 From: Marek Gradzki Date: Tue, 24 May 2016 13:32:26 +0200 Subject: VPP-86: fix array copy in generated JNI code Change-Id: Ic67b3c0623d98c5ee3f1ffa1e1bd9cfb96b233bd Signed-off-by: Marek Gradzki --- vpp-api/java/jvpp/gen/jvpp_c_gen.py | 34 +++-- vpp-api/java/jvpp/gen/jvpp_gen.py | 13 +- .../java/jvpp/org/openvpp/jvpp/test/L2AclTest.java | 142 +++++++++++++++++++++ vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt | 7 +- 4 files changed, 174 insertions(+), 22 deletions(-) create mode 100644 vpp-api/java/jvpp/org/openvpp/jvpp/test/L2AclTest.java diff --git a/vpp-api/java/jvpp/gen/jvpp_c_gen.py b/vpp-api/java/jvpp/gen/jvpp_c_gen.py index e277976c720..c02c826fc49 100644 --- a/vpp-api/java/jvpp/gen/jvpp_c_gen.py +++ b/vpp-api/java/jvpp/gen/jvpp_c_gen.py @@ -89,7 +89,8 @@ u64_struct_setter_template = Template(""" u8_array_struct_setter_template = Template(""" { jsize cnt = (*env)->GetArrayLength (env, ${java_name}); - if (cnt > sizeof(mp->${c_name})) cnt = sizeof(mp->${c_name}); + size_t max_size = ${field_length}; + if (max_size != 0 && cnt > max_size) cnt = max_size; (*env)->GetByteArrayRegion(env, ${java_name}, 0, cnt, (jbyte *)mp->${c_name}); } """) @@ -97,8 +98,11 @@ u8_array_struct_setter_template = Template(""" u32_array_struct_setter_template = Template(""" jint * ${java_name}ArrayElements = (*env)->GetIntArrayElements(env, ${java_name}, NULL); { - int _i; - for (_i = 0; _i < 0; _i++) { + size_t _i; + jsize cnt = (*env)->GetArrayLength (env, ${java_name}); + size_t max_size = ${field_length}; + if (max_size != 0 && cnt > max_size) cnt = max_size; + for (_i = 0; _i < cnt; _i++) { mp->${c_name}[_i] = clib_host_to_net_u32(${java_name}ArrayElements[_i]); } } @@ -180,16 +184,18 @@ def generate_jni_impl(func_list, inputfile): jni_getter=jni_getter) # field setters - for t in zip(f['c_types'], f['args']): + for t in zip(f['c_types'], f['args'], f['lengths']): c_type = t[0] c_name = t[1] + field_length = t[2] java_field_name = util.underscore_to_camelcase(c_name) struct_setter_template = struct_setter_templates[c_type] struct_setters += struct_setter_template.substitute( c_name=c_name, - java_name=java_field_name) + java_name=java_field_name, + field_length=field_length) jni_impl.append(jni_impl_template.substitute( inputfile=inputfile, @@ -221,23 +227,23 @@ u64_dto_field_setter_template = Template(""" """) u8_array_dto_field_setter_template = Template(""" - jbyteArray ${java_name} = (*env)->NewByteArray(env, sizeof(mp->${c_name})); - (*env)->SetByteArrayRegion(env, ${java_name}, 0, sizeof(mp->${c_name}), (const jbyte*)mp->${c_name}); + jbyteArray ${java_name} = (*env)->NewByteArray(env, ${field_length}); + (*env)->SetByteArrayRegion(env, ${java_name}, 0, ${field_length}, (const jbyte*)mp->${c_name}); (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_name}); """) # For each u64 array we get its elements. Then we convert values to host byte order. # All changes to jint* buffer are written to jlongArray (isCopy is set to NULL) u64_array_dto_field_setter_template = Template(""" - jlongArray ${java_name} = (*env)->NewLongArray(env, sizeof(mp->${c_name})); { + jlongArray ${java_name} = (*env)->NewLongArray(env, ${field_length}); jlong * ${java_name}ArrayElements = (*env)->GetLongArrayElements(env, ${java_name}, NULL); - int _i; - for (_i = 0; _i < 0; _i++) { + unsigned int _i; + for (_i = 0; _i < ${field_length}; _i++) { ${java_name}ArrayElements[_i] = clib_net_to_host_u64(mp->${c_name}[_i]); } + (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_name}); } - (*env)->SetObjectField(env, dto, ${java_name}FieldId, ${java_name}); """) dto_field_setter_templates = {'u8': default_dto_field_setter_template, @@ -282,10 +288,11 @@ def generate_msg_handlers(func_list, inputfile): dto_setters = '' # dto setters - for t in zip(f['c_types'], f['types'], f['args']): + for t in zip(f['c_types'], f['types'], f['args'], f['lengths']): c_type = t[0] jni_type = t[1] c_name = t[2] + field_length = t[3] java_field_name = util.underscore_to_camelcase(c_name) jni_signature = util.jni_2_signature_mapping[jni_type] @@ -302,7 +309,8 @@ def generate_msg_handlers(func_list, inputfile): java_name=java_field_name, jni_signature=jni_signature, c_name=c_name, - jni_setter=jni_setter) + jni_setter=jni_setter, + field_length=field_length) handlers.append(msg_handler_template.substitute( inputfile=inputfile, diff --git a/vpp-api/java/jvpp/gen/jvpp_gen.py b/vpp-api/java/jvpp/gen/jvpp_gen.py index 931141e884a..e2ff2adcf14 100755 --- a/vpp-api/java/jvpp/gen/jvpp_gen.py +++ b/vpp-api/java/jvpp/gen/jvpp_gen.py @@ -72,16 +72,19 @@ def get_args(t, filter): def get_types(t, filter): types_list = [] c_types_list = [] + lengths_list = [] for i in t: if not filter(i[1]): continue if len(i) is 3: # array type types_list.append(vpp_2_jni_type_mapping[i[0]] + 'Array') c_types_list.append(i[0] + '[]') + lengths_list.append(i[2]) else: # primitive type types_list.append(vpp_2_jni_type_mapping[i[0]]) c_types_list.append(i[0]) - return types_list, c_types_list + lengths_list.append(0) + return types_list, c_types_list, lengths_list def get_definitions(): @@ -96,18 +99,18 @@ def get_definitions(): # For replies include all the arguments except message_id if util.is_reply(java_name): - types, c_types = get_types(a[1:], is_response_field) + types, c_types, lengths = get_types(a[1:], is_response_field) func_name[a[0]] = dict( [('name', a[0]), ('java_name', java_name), ('args', get_args(a[1:], is_response_field)), ('full_args', get_args(a[1:], lambda x: True)), - ('types', types), ('c_types', c_types)]) + ('types', types), ('c_types', c_types), ('lengths', lengths)]) # For requests skip message_id, client_id and context else: - types, c_types = get_types(a[1:], is_request_field) + types, c_types, lengths = get_types(a[1:], is_request_field) func_name[a[0]] = dict( [('name', a[0]), ('java_name', java_name), ('args', get_args(a[1:], is_request_field)), ('full_args', get_args(a[1:], lambda x: True)), - ('types', types), ('c_types', c_types)]) + ('types', types), ('c_types', c_types), ('lengths', lengths)]) # Indexed by name func_list.append(func_name[a[0]]) diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/L2AclTest.java b/vpp-api/java/jvpp/org/openvpp/jvpp/test/L2AclTest.java new file mode 100644 index 00000000000..8bfa2714463 --- /dev/null +++ b/vpp-api/java/jvpp/org/openvpp/jvpp/test/L2AclTest.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2016 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. + */ + +package org.openvpp.jvpp.test; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import org.openvpp.jvpp.JVppImpl; +import org.openvpp.jvpp.VppJNIConnection; +import org.openvpp.jvpp.dto.ClassifyAddDelSession; +import org.openvpp.jvpp.dto.ClassifyAddDelSessionReply; +import org.openvpp.jvpp.dto.ClassifyAddDelTable; +import org.openvpp.jvpp.dto.ClassifyAddDelTableReply; +import org.openvpp.jvpp.dto.InputAclSetInterface; +import org.openvpp.jvpp.dto.InputAclSetInterfaceReply; +import org.openvpp.jvpp.dto.JVppReply; +import org.openvpp.jvpp.future.FutureJVppFacade; +import org.openvpp.jvpp.future.FutureJVppFacadeCallback; + +/** + *

Tests L2 ACL creation.
+ * Equivalent to the following vppctl commands:
+ * + *

{@code
+ * vppctl classify table mask l2 src
+ * vppctl classify session acl-hit-next deny opaque-index 0 table-index 0 match l2 src 01:02:03:04:05:06
+ * vppctl vppctl set int input acl intfc local0 l2-table 0
+ * }
+ * 
+ * + * To verify invoke:
+ * {@code vppctl sh class table verbose} + */ +public class L2AclTest { + + private static ClassifyAddDelTable createClassifyTable() { + ClassifyAddDelTable request = new ClassifyAddDelTable(); + request.isAdd = 1; + request.tableIndex = ~0; // default + request.nbuckets = 2; + request.memorySize = 2 << 20; + request.nextTableIndex = ~0; // default + request.missNextIndex = ~0; // default + request.skipNVectors = 0; + request.matchNVectors = 1; + request.mask = + new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x00, 0x00}; + return request; + } + + private static ClassifyAddDelSession createClassifySession(final int tableIndex) { + ClassifyAddDelSession request = new ClassifyAddDelSession(); + request.isAdd = 1; + request.tableIndex = tableIndex; + request.hitNextIndex = 0; // deny + request.opaqueIndex = 0; + request.advance = 0; // default + // match 01:02:03:04:05:06 mac address + request.match = + new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, + (byte) 0x05, (byte) 0x06, 0x00, 0x00, 0x00, 0x00}; + return request; + } + + private static InputAclSetInterface aclSetInterface() { + InputAclSetInterface request = new InputAclSetInterface(); + request.isAdd = 1; + request.swIfIndex = 0; + request.ip4TableIndex = ~0; // skip + request.ip6TableIndex = ~0; // skip + request.l2TableIndex = 0; + return request; + } + + private static void print(ClassifyAddDelTableReply reply) { + System.out.printf("ClassifyAddDelTableReply: context=%d, retval=%d, " + + "newTableIndex=%d, skipNVectors=%d, matchNVectors=%d\n", + reply.context, + reply.retval, + reply.newTableIndex, + reply.skipNVectors, + reply.matchNVectors); + } + + private static void print(ClassifyAddDelSessionReply reply) { + System.out.printf("ClassifyAddDelSessionReply: context=%d, retval=%d\n", + reply.context, + reply.retval); + } + + private static void print(final InputAclSetInterfaceReply reply) { + System.out.printf("InputAclSetInterfaceReply: context=%d, retval=%d\n", + reply.context, + reply.retval); + + } + + private static void testL2Acl() throws Exception { + System.out.println("Testing L2 ACLs using Java callback API"); + final Map>> map = new HashMap<>(); + final JVppImpl jvpp = new JVppImpl(VppJNIConnection.create("FutureApiTest", new FutureJVppFacadeCallback(map))); + final FutureJVppFacade jvppFacade = new FutureJVppFacade(jvpp, map); + System.out.println("Successfully connected to VPP"); + Thread.sleep(1000); + + final ClassifyAddDelTableReply classifyAddDelTableReply = + jvppFacade.classifyAddDelTable(createClassifyTable()).toCompletableFuture().get(); + print(classifyAddDelTableReply); + + final ClassifyAddDelSessionReply classifyAddDelSessionReply = + jvppFacade.classifyAddDelSession(createClassifySession(classifyAddDelTableReply.newTableIndex)) + .toCompletableFuture().get(); + print(classifyAddDelSessionReply); + + final InputAclSetInterfaceReply inputAclSetInterfaceReply = + jvppFacade.inputAclSetInterface(aclSetInterface()).toCompletableFuture().get(); + print(inputAclSetInterfaceReply); + + System.out.println("Disconnecting..."); + jvpp.close(); + Thread.sleep(1000); + } + + public static void main(String[] args) throws Exception { + testL2Acl(); + } +} diff --git a/vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt b/vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt index df4100dd973..945e6585f0e 100644 --- a/vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt +++ b/vpp-api/java/jvpp/org/openvpp/jvpp/test/Readme.txt @@ -2,12 +2,11 @@ This package contains basic tests for jvpp. To run the tests: - Make sure VPP is running - From VPP's build-root/ folder execute: - - sudo java -cp .:build-vpp-native/vpp-api/java/jvpp-1.0.0.jar org.openvpp.jvpp.test.ControlPingTest - - sudo java -cp .:build-vpp-native/vpp-api/java/jvpp-1.0.0.jar org.openvpp.jvpp.test.FutureApiTest - - sudo java -cp .:build-vpp-native/vpp-api/java/jvpp-1.0.0.jar org.openvpp.jvpp.test.CallbackApiTest + - sudo java -cp build-vpp-native/vpp-api/java/jvpp-16.06.jar org.openvpp.jvpp.test.[test name] Available tests: ControlPingTest - Simple test executing a single control ping using low level JVpp APIs CallbackApiTest - Similar to ControlPingTest, invokes more complex calls (e.g. interface dump) using low level JVpp APIs FutureApiTest - Execution of more complex calls using Future based JVpp facade -CallbackJVppFacadeTest - Execution of more complex calls using Callback based JVpp facade \ No newline at end of file +CallbackJVppFacadeTest - Execution of more complex calls using Callback based JVpp facade +L2AclTest - Tests L2 ACL creation \ No newline at end of file -- cgit 1.2.3-korg