jvpp: utilize per-message CRCs (VPP-544) 11/4911/2
authorMarek Gradzki <mgradzki@cisco.com>
Fri, 27 Jan 2017 07:57:40 +0000 (08:57 +0100)
committerDamjan Marion <dmarion.lists@gmail.com>
Fri, 27 Jan 2017 19:53:59 +0000 (19:53 +0000)
Since messages ids are no longer statically referenced,
fixes also VPP-611.

Change-Id: Ic8e6ee2b7f1142c185595347984d69350be25ac3
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
src/vpp-api/java/jvpp-acl/jvpp_acl.c
src/vpp-api/java/jvpp-common/jvpp_common.c
src/vpp-api/java/jvpp-common/jvpp_common.h
src/vpp-api/java/jvpp-core/jvpp_core.c
src/vpp-api/java/jvpp-ioamexport/jvpp_ioam_export.c
src/vpp-api/java/jvpp-ioampot/jvpp_ioam_pot.c
src/vpp-api/java/jvpp-ioamtrace/jvpp_ioam_trace.c
src/vpp-api/java/jvpp-registry/jvpp_registry.c
src/vpp-api/java/jvpp-snat/jvpp_snat.c
src/vpp-api/java/jvpp/gen/jvpp_gen.py
src/vpp-api/java/jvpp/gen/jvppgen/jvpp_c_gen.py

index d56abe3..9150ce6 100644 (file)
@@ -74,8 +74,14 @@ JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_acl_JVppAclImpl_init0
     plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback);
     plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback));
 
+    // verify API has not changed since jar generation
+    #define _(N)             \
+        get_message_id(env, #N);  \
+        foreach_supported_api_message;
+    #undef _
+
     #define _(N,n)                                  \
-        vl_msg_api_set_handlers(VL_API_##N + plugin_main->msg_id_base, #n,     \
+        vl_msg_api_set_handlers(get_message_id(env, #N), #n,     \
                 vl_api_##n##_t_handler,             \
                 vl_noop_handler,                    \
                 vl_api_##n##_t_endian,              \
index a161c09..b88c0ea 100644 (file)
@@ -63,3 +63,19 @@ void call_on_error(const char* callName, int contextId, int retval,
     (*env)->CallVoidMethod(env, callbackObject, callbackExcMethod, excObject);
     DEBUG_LOG("CallOnError : Response sent\n");
 }
+
+u32 get_message_id(JNIEnv *env, const char *key) {
+    uword *p = hash_get(jvpp_main.messages_hash, key);
+    if (!p) {
+        jclass exClass = (*env)->FindClass(env, "java/lang/IllegalStateException");
+        char *msgBuf  = clib_mem_alloc(strlen(key) + 40);
+        strcpy(msgBuf, "API mismatch detected: ");
+        strcat(msgBuf, key);
+        strcat(msgBuf, " is missing");
+        DEBUG_LOG("get_message_id : %s\n", msgBuf);
+        (*env)->ThrowNew(env, exClass, msgBuf);
+        clib_mem_free(msgBuf);
+        return 0;
+    }
+    return (u32) p[0];
+}
index bbb203e..34502d0 100644 (file)
@@ -37,6 +37,7 @@ typedef struct {
     /* Convenience */
     unix_shared_memory_queue_t * vl_input_queue;
     u32 my_client_index;
+    uword *messages_hash;
 } jvpp_main_t;
 
 extern jvpp_main_t jvpp_main __attribute__((aligned (64)));
@@ -64,4 +65,10 @@ void call_on_error(const char* callName, int contextId, int retval,
         jclass callbackClass, jobject callbackObject,
         jclass callbackExceptionClass);
 
+/**
+ * Retrieves message id based on message name and crc (key format: name_crc).
+ * Throws java/lang/IllegalStateException on failure.
+ */
+u32 get_message_id(JNIEnv *env, const char* key);
+
 #endif /* __included_jvpp_common_h__ */
index ef4cb8e..c04666b 100644 (file)
@@ -67,8 +67,14 @@ JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_core_JVppCoreImpl_init0
     plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback);
     plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback));
 
+    // verify API has not changed since jar generation
+    #define _(N)             \
+        get_message_id(env, #N);  \
+        foreach_supported_api_message;
+    #undef _
+
     #define _(N,n)                                  \
-        vl_msg_api_set_handlers(VL_API_##N, #n,     \
+        vl_msg_api_set_handlers(get_message_id(env, #N), #n,     \
                 vl_api_##n##_t_handler,             \
                 vl_noop_handler,                    \
                 vl_noop_handler,              \
index 5cda89d..068d2ec 100644 (file)
@@ -74,8 +74,14 @@ JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioamexport_JVppIoamexportImpl_init0
     plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback);
     plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback));
 
+    // verify API has not changed since jar generation
+    #define _(N)             \
+        get_message_id(env, #N);  \
+        foreach_supported_api_message;
+    #undef _
+
     #define _(N,n)                                  \
-        vl_msg_api_set_handlers(VL_API_##N + plugin_main->msg_id_base, #n,     \
+        vl_msg_api_set_handlers(get_message_id(env, #N), #n,     \
                 vl_api_##n##_t_handler,             \
                 vl_noop_handler,                    \
                 vl_api_##n##_t_endian,              \
index 9291dbb..51b6a07 100644 (file)
@@ -74,8 +74,14 @@ JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioampot_JVppIoampotImpl_init0
     plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback);
     plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback));
 
+    // verify API has not changed since jar generation
+    #define _(N)             \
+        get_message_id(env, #N);  \
+        foreach_supported_api_message;
+    #undef _
+
     #define _(N,n)                                  \
-        vl_msg_api_set_handlers(VL_API_##N + plugin_main->msg_id_base, #n,     \
+        vl_msg_api_set_handlers(get_message_id(env, #N), #n,     \
                 vl_api_##n##_t_handler,             \
                 vl_noop_handler,                    \
                 vl_api_##n##_t_endian,              \
index 0bf1788..2f74b5a 100644 (file)
@@ -74,8 +74,14 @@ JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ioamtrace_JVppIoamtraceImpl_init0
     plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback);
     plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback));
 
+    // verify API has not changed since jar generation
+    #define _(N)             \
+        get_message_id(env, #N);  \
+        foreach_supported_api_message;
+    #undef _
+
     #define _(N,n)                                  \
-        vl_msg_api_set_handlers(VL_API_##N + plugin_main->msg_id_base, #n,     \
+        vl_msg_api_set_handlers(get_message_id(env, #N), #n,     \
                 vl_api_##n##_t_handler,             \
                 vl_noop_handler,                    \
                 vl_api_##n##_t_endian,              \
index cbd5e0a..add872d 100644 (file)
@@ -52,16 +52,21 @@ void __stack_chk_guard(void) __attribute__((weak));
 void __stack_chk_guard(void) {
 }
 
+#define CONTROL_PING_MESSAGE "control_ping"
+#define CONTROL_PING_REPLY_MESSAGE "control_ping_reply"
+
 typedef struct {
     /* UThread attachment */
     volatile u32 control_ping_result_ready;
     volatile i32 control_ping_retval;
 
-    /* Control poing callback */
+    /* Control ping callback */
     jobject registryObject;
     jclass registryClass;
     jclass controlPingReplyClass;
     jclass callbackExceptionClass;
+    int control_ping_msg_id;
+    int control_ping_reply_msg_id;
 
     /* Thread cleanup */
     pthread_key_t cleanup_rx_thread_key;
@@ -168,6 +173,41 @@ static void vl_api_control_ping_reply_t_handler(
     out: rm->control_ping_result_ready = 1;
 }
 
+static int find_ping_id() {
+    int rv = 0;
+    jvpp_main_t * jm = &jvpp_main;
+    jvpp_registry_main_t * rm = &jvpp_registry_main;
+    api_main_t *am = &api_main;
+    hash_pair_t *hp;
+    jm->messages_hash = am->msg_index_by_name_and_crc;
+
+    rm->control_ping_msg_id = -1;
+    rm->control_ping_reply_msg_id = -1;
+
+    hash_foreach_pair (hp, jm->messages_hash,
+    ({
+        char *key = (char *)hp->key; // key format: name_crc
+        int msg_name_len = strlen(key) - 9; // ignore crc
+        if (strlen(CONTROL_PING_MESSAGE) == msg_name_len &&
+                strncmp(CONTROL_PING_MESSAGE, (char *)hp->key, msg_name_len) == 0) {
+            rm->control_ping_msg_id = (u32)hp->value[0];
+        }
+        if (strlen(CONTROL_PING_REPLY_MESSAGE) == msg_name_len &&
+                strncmp(CONTROL_PING_REPLY_MESSAGE, (char *)hp->key, msg_name_len) == 0) {
+            rm->control_ping_reply_msg_id  = (u32)hp->value[0];
+        }
+    }));
+    if (rm->control_ping_msg_id == -1) {
+        clib_warning("failed to find id for %s", CONTROL_PING_MESSAGE);
+        rv = -1;
+    }
+    if (rm->control_ping_reply_msg_id == -1) {
+        clib_warning("failed to find id for %s", CONTROL_PING_REPLY_MESSAGE);
+        rv = -1;
+    }
+    return rv;
+}
+
 static int send_initial_control_ping() {
     f64 timeout;
     clib_time_t clib_time;
@@ -180,7 +220,7 @@ static int send_initial_control_ping() {
     rm->control_ping_result_ready = 0;
     mp = vl_msg_api_alloc(sizeof(*mp));
     memset(mp, 0, sizeof(*mp));
-    mp->_vl_msg_id = ntohs(VL_API_CONTROL_PING);
+    mp->_vl_msg_id = ntohs(rm->control_ping_msg_id);
     mp->client_index = jm->my_client_index;
 
     // send message:
@@ -197,7 +237,7 @@ static int send_initial_control_ping() {
     }
 
     if (rv != 0) {
-        clib_warning("common: first control ping failed: %d", rv);
+        clib_warning("first control ping failed: %d", rv);
     }
 
     return rv;
@@ -206,6 +246,7 @@ static int send_initial_control_ping() {
 static int connect_to_vpe(char *name) {
     jvpp_main_t * jm = &jvpp_main;
     api_main_t * am = &api_main;
+    jvpp_registry_main_t * rm = &jvpp_registry_main;
 
     if (vl_client_connect_to_vlib("/vpe-api", name, 32) < 0)
         return -1;
@@ -214,7 +255,10 @@ static int connect_to_vpe(char *name) {
 
     jm->vl_input_queue = am->shmem_hdr->vl_input_queue;
 
-    vl_msg_api_set_handlers(VL_API_CONTROL_PING_REPLY, "control_ping_reply",
+    if (find_ping_id() < 0)
+        return -1;
+
+    vl_msg_api_set_handlers(rm->control_ping_reply_msg_id, CONTROL_PING_REPLY_MESSAGE,
             vl_api_control_ping_reply_t_handler, vl_noop_handler,
             vl_api_control_ping_reply_t_endian,
             vl_api_control_ping_reply_t_print,
@@ -286,7 +330,7 @@ JNIEXPORT jint JNICALL Java_io_fd_vpp_jvpp_JVppRegistryImpl_controlPing0(
 
     mp = vl_msg_api_alloc(sizeof(*mp));
     memset(mp, 0, sizeof(*mp));
-    mp->_vl_msg_id = ntohs(VL_API_CONTROL_PING);
+    mp->_vl_msg_id = ntohs(rm->control_ping_msg_id);
     mp->client_index = jm->my_client_index;
     mp->context = clib_host_to_net_u32(my_context_id);
 
index 1095b6e..c4d1afe 100644 (file)
@@ -74,8 +74,14 @@ JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_snat_JVppSnatImpl_init0
     plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback);
     plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback));
 
+    // verify API has not changed since jar generation
+    #define _(N)             \
+        get_message_id(env, #N);
+        foreach_supported_api_message;
+    #undef _
+
     #define _(N,n)                                  \
-        vl_msg_api_set_handlers(VL_API_##N + plugin_main->msg_id_base, #n,     \
+        vl_msg_api_set_handlers(get_message_id(env, #N), #n,     \
                 vl_api_##n##_t_handler,             \
                 vl_noop_handler,                    \
                 vl_api_##n##_t_endian,              \
index f51b11d..2a5ada9 100755 (executable)
@@ -6,7 +6,7 @@
 # You may obtain a copy of the License at:
 #
 #     http://www.apache.org/licenses/LICENSE-2.0
-# l
+#
 # 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.
index 611171c..5b0fbc9 100644 (file)
@@ -130,7 +130,7 @@ JNIEXPORT jint JNICALL Java_io_fd_vpp_jvpp_${plugin_name}_JVpp${java_plugin_name
     // create message:
     mp = vl_msg_api_alloc(sizeof(*mp));
     memset (mp, 0, sizeof (*mp));
-    mp->_vl_msg_id = ntohs (VL_API_${c_name_uppercase} + plugin_main->msg_id_base);
+    mp->_vl_msg_id = ntohs (get_message_id(env, "${c_name}_${crc}"));
     mp->client_index = plugin_main->my_client_index;
     mp->context = clib_host_to_net_u32 (my_context_id);
 
@@ -181,6 +181,7 @@ def generate_jni_impl(func_list, plugin_name, inputfile):
                 field_name=camel_case_function_name,
                 c_name_uppercase=f_name_uppercase,
                 c_name=f_name,
+                crc=f['crc'],
                 plugin_name=plugin_name,
                 java_plugin_name=plugin_name.title(),
                 request_class=request_class,
@@ -282,7 +283,7 @@ def generate_msg_handlers(func_list, plugin_name, inputfile):
     return "\n".join(handlers)
 
 
-handler_registration_template = Template("""_(${upercase_name}, ${name}) \\
+handler_registration_template = Template("""_(${name}_${crc}, ${name}) \\
 """)
 
 
@@ -298,11 +299,30 @@ def generate_handler_registration(func_list):
 
         handler_registration.append(handler_registration_template.substitute(
             name=name,
-            upercase_name=name.upper()))
+            crc=f['crc']))
 
     return "".join(handler_registration)
 
 
+api_verification_template = Template("""_(${name}_${crc}) \\
+""")
+
+
+def generate_api_verification(func_list):
+    api_verification = ["#define foreach_supported_api_message \\\n"]
+    for f in func_list:
+        name = f['name']
+
+        if util.is_ignored(name):
+            continue
+
+        api_verification.append(api_verification_template.substitute(
+            name=name,
+            crc=f['crc']))
+
+    return "".join(api_verification)
+
+
 jvpp_c_template = Template("""/**
  * This file contains JNI bindings for jvpp Java API.
  * It was generated by jvpp_c_gen.py based on $inputfile
@@ -312,6 +332,9 @@ jvpp_c_template = Template("""/**
 // JAVA class reference cache
 $class_cache
 
+// List of supported API messages used for verification
+$api_verification
+
 // JNI bindings
 $jni_implementations
 
@@ -330,11 +353,13 @@ def generate_jvpp(func_list, plugin_name, inputfile, path):
     jni_impl = generate_jni_impl(func_list, plugin_name, inputfile)
     msg_handlers = generate_msg_handlers(func_list, plugin_name, inputfile)
     handler_registration = generate_handler_registration(func_list)
+    api_verification = generate_api_verification(func_list)
 
     jvpp_c_file = open("%s/jvpp_%s_gen.h" % (path, plugin_name), 'w')
     jvpp_c_file.write(jvpp_c_template.substitute(
             inputfile=inputfile,
             class_cache=class_cache,
+            api_verification=api_verification,
             jni_implementations=jni_impl,
             msg_handlers=msg_handlers,
             handler_registration=handler_registration))