blob: 4274c31dd91c9a340959e6c7f5dead0d970b1e93 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include <vnet/vnet.h>
16
17#define vl_api_version(n,v) static u32 vpe_api_version = (v);
18#include <api/vpe.api.h>
19#undef vl_api_version
20
21#include <jni.h>
22#include <japi/vppjni.h>
23#include <japi/vppjni_bridge_domain.h>
24#include <japi/org_openvpp_vppjapi_vppConn.h>
25#include <japi/org_openvpp_vppjapi_vppApi.h>
26
27#include <api/vpe_msg_enum.h>
28#define vl_typedefs /* define message structures */
29#include <api/vpe_all_api_h.h>
30#undef vl_typedefs
31
32#define vl_endianfun
33#include <api/vpe_all_api_h.h>
34#undef vl_endianfun
35
36/* instantiate all the print functions we know about */
37#define vl_print(handle, ...)
38#define vl_printfun
39#include <api/vpe_all_api_h.h>
40#undef vl_printfun
41
42static int connect_to_vpe(char *name);
43
44/*
45 * The Java runtime isn't compile w/ -fstack-protector,
46 * so we have to supply missing external references for the
47 * regular vpp libraries. Weak reference in case folks get religion
48 * at a later date...
49 */
50void __stack_chk_guard (void) __attribute__((weak));
51void __stack_chk_guard (void) { }
52
53void vl_client_add_api_signatures (vl_api_memclnt_create_t *mp)
54{
55 /*
56 * Send the main API signature in slot 0. This bit of code must
57 * match the checks in ../vpe/api/api.c: vl_msg_api_version_check().
58 */
59 mp->api_versions[0] = clib_host_to_net_u32 (vpe_api_version);
60}
61
62/* Note: non-static, called once to set up the initial intfc table */
63static int sw_interface_dump (vppjni_main_t * jm)
64{
65 vl_api_sw_interface_dump_t *mp;
66 f64 timeout;
67 hash_pair_t * p;
68 name_sort_t * nses = 0, * ns;
69 sw_interface_subif_t * sub = NULL;
70
71 /* Toss the old name table */
72 hash_foreach_pair (p, jm->sw_if_index_by_interface_name,
73 ({
74 vec_add2 (nses, ns, 1);
75 ns->name = (u8 *)(p->key);
76 ns->value = (u32) p->value[0];
77 }));
78
79 hash_free (jm->sw_if_index_by_interface_name);
80
81 vec_foreach (ns, nses)
82 vec_free (ns->name);
83
84 vec_free (nses);
85
86 vec_foreach (sub, jm->sw_if_subif_table) {
87 vec_free (sub->interface_name);
88 }
89 vec_free (jm->sw_if_subif_table);
90
91 /* recreate the interface name hash table */
92 jm->sw_if_index_by_interface_name
93 = hash_create_string (0, sizeof(uword));
94
95 /* Get list of ethernets */
96 M(SW_INTERFACE_DUMP, sw_interface_dump);
97 mp->name_filter_valid = 1;
98 strncpy ((char *) mp->name_filter, "Ether", sizeof(mp->name_filter-1));
99 S;
100
101 /* and local / loopback interfaces */
102 M(SW_INTERFACE_DUMP, sw_interface_dump);
103 mp->name_filter_valid = 1;
104 strncpy ((char *) mp->name_filter, "lo", sizeof(mp->name_filter-1));
105 S;
106
107 /* and vxlan tunnel interfaces */
108 M(SW_INTERFACE_DUMP, sw_interface_dump);
109 mp->name_filter_valid = 1;
110 strncpy ((char *) mp->name_filter, "vxlan", sizeof(mp->name_filter-1));
111 S;
112
113 /* and tap tunnel interfaces */
114 M(SW_INTERFACE_DUMP, sw_interface_dump);
115 mp->name_filter_valid = 1;
116 strncpy ((char *) mp->name_filter, "tap", sizeof(mp->name_filter-1));
117 S;
118
119 /* and l2tpv3 tunnel interfaces */
120 M(SW_INTERFACE_DUMP, sw_interface_dump);
121 mp->name_filter_valid = 1;
122 strncpy ((char *) mp->name_filter, "l2tpv3_tunnel",
123 sizeof(mp->name_filter-1));
124 S;
125
126 /* Use a control ping for synchronization */
127 {
128 vl_api_control_ping_t * mp;
129 M(CONTROL_PING, control_ping);
130 S;
131 }
132 W;
133}
134
135JNIEXPORT jobject JNICALL Java_org_openvpp_vppjapi_vppConn_getVppVersion
136 (JNIEnv *env, jobject obj)
137{
138 vppjni_main_t * jm = &vppjni_main;
139 jmethodID constr;
140 // TODO: cache this
141 jclass cls = (*env)->FindClass(env, "org/openvpp/vppjapi/vppVersion");
142 if ((*env)->ExceptionCheck(env)) {
143 (*env)->ExceptionDescribe(env);
144 return NULL;
145 }
146
147 constr = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
148 if ((*env)->ExceptionCheck(env)) {
149 (*env)->ExceptionDescribe(env);
150 return NULL;
151 }
152
153 vppjni_lock (jm, 11);
154 jstring progName = (*env)->NewStringUTF(env, (char *)jm->program_name);
155 jstring buildDir = (*env)->NewStringUTF(env, (char *)jm->build_directory);
Damjan Mariona0d4a1a2015-12-12 14:40:59 +0100156 jstring version = (*env)->NewStringUTF(env, (char *)jm->version);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700157 jstring buildDate = (*env)->NewStringUTF(env, (char *)jm->build_date);
158 vppjni_unlock (jm);
159
Damjan Mariona0d4a1a2015-12-12 14:40:59 +0100160 return (*env)->NewObject(env, cls, constr, progName, buildDir, version, buildDate);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700161}
162
163static int jm_show_version (vppjni_main_t *jm)
164{
165 int rv;
166 vl_api_show_version_t *mp;
167 f64 timeout;
168
169 vppjni_lock (jm, 10);
170 M(SHOW_VERSION, show_version);
171
172 S;
173 vppjni_unlock (jm);
174 WNR;
175 return rv;
176}
177
178static int jm_stats_enable_disable (vppjni_main_t *jm, u8 enable)
179{
180 vl_api_want_stats_t * mp;
181 f64 timeout;
182 int rv;
183
184 vppjni_lock (jm, 13);
185
186 M(WANT_STATS, want_stats);
187
188 mp->enable_disable = enable;
189
190 S;
191 vppjni_unlock (jm);
192 WNR;
193
194 // already subscribed / already disabled (it's ok)
195 if (rv == -2 || rv == -3)
196 rv = 0;
197 return rv;
198}
199
200JNIEXPORT jint JNICALL Java_org_openvpp_vppjapi_vppConn_clientConnect
201 (JNIEnv *env, jobject obj, jstring clientName)
202{
203 int rv;
204 const char *client_name;
205 void vl_msg_reply_handler_hookup(void);
206 vppjni_main_t * jm = &vppjni_main;
207 api_main_t * am = &api_main;
208 u8 * heap;
209 mheap_t * h;
210 f64 timeout;
211
212 /*
213 * Bail out now if we're not running as root
214 */
215 if (geteuid() != 0)
216 return -1;
217
218 if (jm->is_connected)
219 return -2;
220
221 if (jm->heap == 0)
222 clib_mem_init (0, 128<<20);
223
224 heap = clib_mem_get_per_cpu_heap();
225 h = mheap_header (heap);
226
227 client_name = (*env)->GetStringUTFChars (env, clientName, 0);
228
229 clib_time_init (&jm->clib_time);
230
231 rv = connect_to_vpe ((char *) client_name);
232
233 if (rv < 0)
234 clib_warning ("connection failed, rv %d", rv);
235
236 (*env)->ReleaseStringUTFChars (env, clientName, client_name);
237
238 if (rv == 0)
239 {
240 vl_msg_reply_handler_hookup ();
241 jm->is_connected = 1;
242 /* make the main heap thread-safe */
243 h->flags |= MHEAP_FLAG_THREAD_SAFE;
244
245 jm->reply_hash = hash_create (0, sizeof (uword));
246 jm->callback_hash = hash_create (0, sizeof (uword));
247 jm->ping_hash = hash_create (0, sizeof (uword));
248 jm->api_main = am;
249 vjbd_main_init(&jm->vjbd_main);
250 jm->sw_if_index_by_interface_name =
251 hash_create_string (0, sizeof (uword));
252
253 {
254 // call control ping first to attach rx thread to java thread
255 vl_api_control_ping_t * mp;
256 M(CONTROL_PING, control_ping);
257 S;
258 WNR;
259
260 if (rv != 0) {
261 clib_warning ("first control ping failed: %d", rv);
262 }
263 }
264 rv = jm_show_version(jm);
265 if (rv != 0)
266 clib_warning ("unable to retrieve vpp version (rv: %d)", rv);
267 rv = sw_interface_dump(jm);
268 if (rv != 0)
269 clib_warning ("unable to retrieve interface list (rv: %d)", rv);
270 rv = jm_stats_enable_disable(jm, 1);
271 if (rv != 0)
272 clib_warning ("unable to subscribe to stats (rv: %d)", rv);
273 }
274 clib_warning ("clientConnect result: %d", rv);
275
276 return rv;
277}
278
279JNIEXPORT void JNICALL Java_org_openvpp_vppjapi_vppConn_clientDisconnect
280 (JNIEnv *env, jobject obj)
281{
282 u8 *save_heap;
283 vppjni_main_t * jm = &vppjni_main;
284 vl_client_disconnect_from_vlib();
285
286 save_heap = jm->heap;
287 memset (jm, 0, sizeof (*jm));
288 jm->heap = save_heap;
289}
290
291void vl_api_generic_reply_handler (vl_api_generic_reply_t *mp)
292{
293 api_main_t * am = &api_main;
294 u16 msg_id = clib_net_to_host_u16 (mp->_vl_msg_id);
295 trace_cfg_t *cfgp;
296 i32 retval = clib_net_to_host_u32 (mp->retval);
297 int total_bytes = sizeof(mp);
298 vppjni_main_t * jm = &vppjni_main;
299 u8 * saved_reply = 0;
300 u32 context = clib_host_to_net_u32 (mp->context);
301
302 cfgp = am->api_trace_cfg + msg_id;
303
304 if (!cfgp)
305 clib_warning ("msg id %d: no trace configuration\n", msg_id);
306 else
307 total_bytes = cfgp->size;
308
309 jm->context_id_received = context;
310
311 clib_warning("Received generic reply for msg id %d", msg_id);
312
313 /* A generic reply, successful, we're done */
314 if (retval >= 0 && total_bytes == sizeof(*mp))
315 return;
316
317 /* Save the reply */
318 vec_validate (saved_reply, total_bytes - 1);
319 memcpy (saved_reply, mp, total_bytes);
320
321 vppjni_lock (jm, 2);
322 hash_set (jm->reply_hash, context, saved_reply);
323 jm->saved_reply_count ++;
324 vppjni_unlock (jm);
325}
326
327JNIEXPORT jint JNICALL Java_org_openvpp_vppjapi_vppConn_getRetval
328(JNIEnv * env, jobject obj, jint context, jint release)
329{
330 vppjni_main_t * jm = &vppjni_main;
331 vl_api_generic_reply_t * mp;
332 uword * p;
333 int rv = 0;
334
335 /* Dunno yet? */
336 if (context > jm->context_id_received)
337 return (VNET_API_ERROR_RESPONSE_NOT_READY);
338
339 vppjni_lock (jm, 1);
340 p = hash_get (jm->reply_hash, context);
341
342 /*
343 * Two cases: a generic "yes" reply - won't be in the hash table
344 * or "no", or "more data" which will be in the table.
345 */
346 if (p == 0)
347 goto out;
348
349 mp = (vl_api_generic_reply_t *) (p[0]);
350 rv = clib_net_to_host_u32 (mp->retval);
351
352 if (release)
353 {
354 u8 * free_me = (u8 *) mp;
355 vec_free (free_me);
356 hash_unset (jm->reply_hash, context);
357 jm->saved_reply_count --;
358 }
359
360out:
361 vppjni_unlock (jm);
362 return (rv);
363}
364
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500365static int
366name_sort_cmp (void * a1, void * a2)
367{
368 name_sort_t * n1 = a1;
369 name_sort_t * n2 = a2;
370
371 return strcmp ((char *)n1->name, (char *)n2->name);
372}
373
Ed Warnickecb9cada2015-12-08 15:45:58 -0700374JNIEXPORT jstring JNICALL Java_org_openvpp_vppjapi_vppConn_getInterfaceList
375 (JNIEnv * env, jobject obj, jstring name_filter)
376{
377 vppjni_main_t * jm = &vppjni_main;
378 jstring rv;
379 hash_pair_t * p;
380 name_sort_t * nses = 0, * ns;
381 const char *this_name;
382 const char * nf = (*env)->GetStringUTFChars (env, name_filter, NULL);
383 u8 * s = 0;
384 char *strcasestr (const char *, const char *);
385
386 vppjni_lock (jm, 4);
387
388 hash_foreach_pair (p, jm->sw_if_index_by_interface_name,
389 ({
390 this_name = (const char *)(p->key);
391 if (strlen (nf) == 0 || strcasestr (this_name, nf))
392 {
393 vec_add2 (nses, ns, 1);
394 ns->name = (u8 *)(p->key);
395 ns->value = (u32) p->value[0];
396 }
397 }));
398
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500399 vec_sort_with_function (nses, name_sort_cmp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700400
401 vec_foreach (ns, nses)
402 s = format (s, "%s: %d, ", ns->name, ns->value);
403
404 _vec_len (s) = vec_len (s) - 2;
405 vec_terminate_c_string (s);
406 vppjni_unlock (jm);
407
408 vec_free (nses);
409
410 (*env)->ReleaseStringUTFChars (env, name_filter, nf);
411
412 rv = (*env)->NewStringUTF (env, (char *) s);
413 vec_free (s);
414
415 return rv;
416}
417
418JNIEXPORT jint JNICALL Java_org_openvpp_vppjapi_vppConn_swIfIndexFromName
419 (JNIEnv * env, jobject obj, jstring interfaceName)
420{
421 vppjni_main_t * jm = &vppjni_main;
422 jint rv = -1;
423 const char * if_name = (*env)->GetStringUTFChars (env, interfaceName, NULL);
424 uword * p;
425
426 vppjni_lock (jm, 5);
427
428 p = hash_get_mem (jm->sw_if_index_by_interface_name, if_name);
429
430 if (p != 0)
431 rv = (jint) p[0];
432
433 vppjni_unlock (jm);
434
435 (*env)->ReleaseStringUTFChars (env, interfaceName, if_name);
436
437 return rv;
438}
439
440JNIEXPORT jobject JNICALL Java_org_openvpp_vppjapi_vppConn_getInterfaceCounters
441(JNIEnv * env, jobject obj, jint swIfIndex)
442{
443 vppjni_main_t * jm = &vppjni_main;
444 sw_interface_stats_t *s;
445 u32 sw_if_index = swIfIndex;
446 jmethodID constr;
447 jobject result = NULL;
448
449 // TODO: cache this
450 jclass cls = (*env)->FindClass(env, "org/openvpp/vppjapi/vppInterfaceCounters");
451 if ((*env)->ExceptionCheck(env)) {
452 (*env)->ExceptionDescribe(env);
453 return NULL;
454 }
455
456 constr = (*env)->GetMethodID(env, cls, "<init>", "(JJJJJJJJJJJJJJJJJJJJJJ)V");
457 if ((*env)->ExceptionCheck(env)) {
458 (*env)->ExceptionDescribe(env);
459 return NULL;
460 }
461
462 vppjni_lock (jm, 16);
463
464 if (sw_if_index >= vec_len(jm->sw_if_stats_by_sw_if_index)) {
465 goto out;
466 }
467 s = &jm->sw_if_stats_by_sw_if_index[sw_if_index];
468 if (!s->valid) {
469 goto out;
470 }
471
472 result = (*env)->NewObject(env, cls, constr,
473 s->rx.octets, s->rx.pkts.ip4, s->rx.pkts.ip6, s->rx.pkts.unicast,
474 s->rx.pkts.multicast, s->rx.pkts.broadcast, s->rx.pkts.discard,
475 s->rx.pkts.fifo_full, s->rx.pkts.error, s->rx.pkts.unknown_proto,
476 s->rx.pkts.miss,
477 s->tx.octets, s->tx.pkts.ip4, s->tx.pkts.ip6, s->tx.pkts.unicast,
478 s->tx.pkts.multicast, s->tx.pkts.broadcast, s->tx.pkts.discard,
479 s->tx.pkts.fifo_full, s->tx.pkts.error, s->tx.pkts.unknown_proto,
480 s->tx.pkts.miss);
481
482out:
483 vppjni_unlock (jm);
484 return result;
485}
486
487JNIEXPORT jstring JNICALL Java_org_openvpp_vppjapi_vppConn_interfaceNameFromSwIfIndex
488(JNIEnv * env, jobject obj, jint swIfIndex)
489{
490 vppjni_main_t * jm = &vppjni_main;
491 sw_interface_details_t *sw_if_details;
492 u32 sw_if_index;
493 jstring ifname = NULL;
494
495 vppjni_lock (jm, 8);
496
497 sw_if_index = swIfIndex;
498
499 if (sw_if_index >= vec_len(jm->sw_if_table)) {
500 goto out;
501 }
502 sw_if_details = &jm->sw_if_table[sw_if_index];
503 if (!sw_if_details->valid) {
504 goto out;
505 }
506
507 u8 * s = format (0, "%s%c", sw_if_details->interface_name, 0);
508 ifname = (*env)->NewStringUTF(env, (char *)s);
509
510out:
511 vppjni_unlock (jm);
512
513 return ifname;
514}
515
516JNIEXPORT void JNICALL Java_org_openvpp_vppjapi_vppConn_clearInterfaceTable
517(JNIEnv * env, jobject obj)
518{
519 vppjni_main_t * jm = &vppjni_main;
520
521 vppjni_lock (jm, 10);
522
523 vec_reset_length(jm->sw_if_table);
524
525 vppjni_unlock (jm);
526}
527
528
529JNIEXPORT jint JNICALL Java_org_openvpp_vppjapi_vppConn_swInterfaceDump
530(JNIEnv * env, jobject obj, jbyte name_filter_valid, jbyteArray name_filter)
531{
532 vppjni_main_t *jm = &vppjni_main;
533 f64 timeout;
534 vl_api_sw_interface_dump_t * mp;
535 u32 my_context_id;
536 int rv;
537 rv = vppjni_sanity_check (jm);
538 if (rv) return rv;
539 vppjni_lock (jm, 7);
540 my_context_id = vppjni_get_context_id (jm);
541 jbyte * name_filterP = (*env)->GetByteArrayElements (env, name_filter, NULL);
542 int cnt = (*env)->GetArrayLength (env, name_filter);
543
544 M(SW_INTERFACE_DUMP, sw_interface_dump);
545 mp->context = clib_host_to_net_u32 (my_context_id);
546 mp->name_filter_valid = name_filter_valid;
547
548 if (cnt > sizeof(mp->name_filter))
549 cnt = sizeof(mp->name_filter);
550
551 memcpy ((char *) mp->name_filter, name_filterP, cnt);
552 (*env)->ReleaseByteArrayElements (env, name_filter, name_filterP, 0);
553
554 clib_warning("interface filter (%d, %s, len: %d)", mp->name_filter_valid, (char *)mp->name_filter, cnt);
555
556 hash_set (jm->callback_hash, my_context_id, (*env)->NewGlobalRef(env, obj));
557 jm->collect_indices = 1;
558
559 S;
560 {
561 // now send control ping so we know when it ends
562 vl_api_control_ping_t * mp;
563 M(CONTROL_PING, control_ping);
564 mp->context = clib_host_to_net_u32 (my_context_id);
565
566 // this control ping will mark end of interface dump
567 hash_set (jm->ping_hash, my_context_id, VL_API_SW_INTERFACE_DUMP);
568
569 S;
570 }
571 vppjni_unlock (jm);
572 WNR;
573 return my_context_id;
574}
575
576static int sw_if_dump_call_all_callbacks (jobject obj)
577{
578 vppjni_main_t * jm = &vppjni_main;
579 sw_interface_details_t *sw_if_details;
580 int rc = 0;
581 u32 i;
582
583 JNIEnv *env = jm->jenv;
584
585 for (i = 0; i < vec_len(jm->sw_if_dump_if_indices); i++) {
586 u32 sw_if_index = jm->sw_if_dump_if_indices[i];
587 ASSERT(sw_if_index < vec_len(jm->sw_if_table));
588 sw_if_details = &jm->sw_if_table[sw_if_index];
589 ASSERT(sw_if_details->valid);
590
591 u8 * s = format (0, "%s%c", sw_if_details->interface_name, 0);
592
593 jstring ifname = (*env)->NewStringUTF(env, (char *)s);
594 jint ifIndex = sw_if_details->sw_if_index;
595 jint supIfIndex = sw_if_details->sup_sw_if_index;
596 jbyteArray physAddr = (*env)->NewByteArray(env,
597 sw_if_details->l2_address_length);
598 (*env)->SetByteArrayRegion(env, physAddr, 0,
599 sw_if_details->l2_address_length,
600 (signed char*)sw_if_details->l2_address);
601 jint subId = sw_if_details->sub_id;
602 jint subOuterVlanId = sw_if_details->sub_outer_vlan_id;
603 jint subInnerVlanId = sw_if_details->sub_inner_vlan_id;
604 jint vtrOp = sw_if_details->vtr_op;
605 jint vtrPushDot1q = sw_if_details->vtr_push_dot1q;
606 jint vtrTag1 = sw_if_details->vtr_tag1;
607 jint vtrTag2 = sw_if_details->vtr_tag2;
608
609 jmethodID jmtdIfDetails = jm->jmtdIfDetails;
610
611 jbyte adminUpDown = sw_if_details->admin_up_down;
612 jbyte linkUpDown = sw_if_details->link_up_down;
613 jbyte linkDuplex = sw_if_details->link_duplex;
614 jbyte linkSpeed = sw_if_details->link_speed;
615 jbyte subDot1ad = sw_if_details->sub_dot1ad;
616 jbyte subNumberOfTags = sw_if_details->sub_number_of_tags;
617 jbyte subExactMatch = sw_if_details->sub_exact_match;
618 jbyte subDefault = sw_if_details->sub_default;
619 jbyte subOuterVlanIdAny = sw_if_details->sub_outer_vlan_id_any;
620 jbyte subInnerVlanIdAny = sw_if_details->sub_inner_vlan_id_any;
621
622 clib_warning("Method: %p, Calling method", jm->jmtdIfDetails);
623 (*env)->CallVoidMethod(env, obj, jmtdIfDetails, ifIndex, ifname,
624 supIfIndex, physAddr, adminUpDown, linkUpDown,
625 linkDuplex, linkSpeed, subId, subDot1ad,
626 subNumberOfTags, subOuterVlanId, subInnerVlanId,
627 subExactMatch, subDefault, subOuterVlanIdAny,
628 subInnerVlanIdAny, vtrOp, vtrPushDot1q, vtrTag1, vtrTag2);
629 if ((*env)->ExceptionCheck(env)) {
630 (*env)->ExceptionDescribe(env);
631 rc = 1;
632 goto out;
633 }
634 }
635 clib_warning("Method: %p, Calling method (null arg)", jm->jmtdIfDetails);
636 jmethodID jmtdIfDetails = jm->jmtdIfDetails;
637 (*env)->CallVoidMethod(env, obj, jmtdIfDetails, -1, NULL, -1, NULL, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
638 if ((*env)->ExceptionCheck(env)) {
639 (*env)->ExceptionDescribe(env);
640 rc = 1;
641 goto out;
642 }
643
644 clib_warning("Done");
645
646out:
647 jm->collect_indices = 0;
648 vec_reset_length(jm->sw_if_dump_if_indices);
649 return rc;
650}
651
652JNIEXPORT jint JNICALL Java_org_openvpp_vppjapi_vppConn_findOrAddBridgeDomainId
653 (JNIEnv * env, jobject obj, jstring bridgeDomain)
654{
655 vppjni_main_t * jm = &vppjni_main;
656 jint rv = -1;
657 const char * bd_name = (*env)->GetStringUTFChars (env, bridgeDomain, NULL);
658
659 vppjni_lock (jm, 6);
660
661 rv = (jint)vjbd_find_or_add_bd (&jm->vjbd_main, (u8 *)bd_name);
662
663 vppjni_unlock (jm);
664
665 (*env)->ReleaseStringUTFChars (env, bridgeDomain, bd_name);
666
667 return rv;
668}
669
670JNIEXPORT jint JNICALL Java_org_openvpp_vppjapi_vppConn_bridgeDomainIdFromName
671 (JNIEnv * env, jobject obj, jstring bridgeDomain)
672{
673 vppjni_main_t * jm = &vppjni_main;
674 jint rv = -1;
675 const char * bd_name = (*env)->GetStringUTFChars(env, bridgeDomain, NULL);
676
677 vppjni_lock(jm, 7);
678
679 rv = (jint)vjbd_id_from_name(&jm->vjbd_main, (u8 *)bd_name);
680
681 vppjni_unlock(jm);
682
683 (*env)->ReleaseStringUTFChars(env, bridgeDomain, bd_name);
684
685 return rv;
686}
687
688JNIEXPORT jint JNICALL Java_org_openvpp_vppjapi_vppConn_bridgeDomainIdFromInterfaceName
689 (JNIEnv * env, jobject obj, jstring interfaceName)
690{
691 vppjni_main_t * jm = &vppjni_main;
692 vjbd_main_t * bdm = &jm->vjbd_main;
693 u32 sw_if_index;
694 jint rv = -1;
695 const char * if_name;
696 uword * p;
697
698 if_name = (*env)->GetStringUTFChars (env, interfaceName, NULL);
699
700 vppjni_lock (jm, 14);
701
702 p = hash_get_mem (jm->sw_if_index_by_interface_name, if_name);
703
704 if (p != 0) {
705 sw_if_index = (jint) p[0];
706 p = hash_get (bdm->bd_id_by_sw_if_index, sw_if_index);
707 if (p != 0) {
708 rv = (jint) p[0];
709 }
710 }
711
712 vppjni_unlock (jm);
713
714 (*env)->ReleaseStringUTFChars (env, interfaceName, if_name);
715
716 return rv;
717}
718
719/*
720 * Special-case: build the interface table, maintain
721 * the next loopback sw_if_index vbl.
722 */
723static void vl_api_sw_interface_details_t_handler
724(vl_api_sw_interface_details_t * mp)
725{
726 vppjni_main_t * jm = &vppjni_main;
727 static sw_interface_details_t empty_sw_if_details = {0,};
728 sw_interface_details_t *sw_if_details;
729 u32 sw_if_index;
730
731 vppjni_lock (jm, 1);
732
733 sw_if_index = ntohl (mp->sw_if_index);
734
735 u8 * s = format (0, "%s%c", mp->interface_name, 0);
736
737 if (jm->collect_indices) {
738 u32 pos = vec_len(jm->sw_if_dump_if_indices);
739 vec_validate(jm->sw_if_dump_if_indices, pos);
740 jm->sw_if_dump_if_indices[pos] = sw_if_index;
741 }
742
743 vec_validate_init_empty(jm->sw_if_table, sw_if_index, empty_sw_if_details);
744 sw_if_details = &jm->sw_if_table[sw_if_index];
745 sw_if_details->valid = 1;
746
747 snprintf((char *)sw_if_details->interface_name,
748 sizeof(sw_if_details->interface_name), "%s", (char *)s);
749 sw_if_details->sw_if_index = sw_if_index;
750 sw_if_details->sup_sw_if_index = ntohl(mp->sup_sw_if_index);
751 sw_if_details->l2_address_length = ntohl (mp->l2_address_length);
752 ASSERT(sw_if_details->l2_address_length <= sizeof(sw_if_details->l2_address));
753 memcpy(sw_if_details->l2_address, mp->l2_address,
754 sw_if_details->l2_address_length);
755 sw_if_details->sub_id = ntohl (mp->sub_id);
756 sw_if_details->sub_outer_vlan_id = ntohl (mp->sub_outer_vlan_id);
757 sw_if_details->sub_inner_vlan_id = ntohl (mp->sub_inner_vlan_id);
758 sw_if_details->vtr_op = ntohl (mp->vtr_op);
759 sw_if_details->vtr_push_dot1q = ntohl (mp->vtr_push_dot1q);
760 sw_if_details->vtr_tag1 = ntohl (mp->vtr_tag1);
761 sw_if_details->vtr_tag2 = ntohl (mp->vtr_tag2);
762
763 sw_if_details->admin_up_down = mp->admin_up_down;
764 sw_if_details->link_up_down = mp->link_up_down;
765 sw_if_details->link_duplex = mp->link_duplex;
766 sw_if_details->link_speed = mp->link_speed;
767 sw_if_details->sub_dot1ad = mp->sub_dot1ad;
768 sw_if_details->sub_number_of_tags = mp->sub_number_of_tags;
769 sw_if_details->sub_exact_match = mp->sub_exact_match;
770 sw_if_details->sub_default = mp->sub_default;
771 sw_if_details->sub_outer_vlan_id_any = mp->sub_outer_vlan_id_any;
772 sw_if_details->sub_inner_vlan_id_any = mp->sub_inner_vlan_id_any;
773
774 hash_set_mem (jm->sw_if_index_by_interface_name, s, sw_if_index);
775 clib_warning("Got interface %s", (char *)s);
776
777 /* In sub interface case, fill the sub interface table entry */
778 if (mp->sw_if_index != mp->sup_sw_if_index) {
779 sw_interface_subif_t * sub = NULL;
780
781 vec_add2(jm->sw_if_subif_table, sub, 1);
782
783 vec_validate(sub->interface_name, strlen((char *)s) + 1);
784 strncpy((char *)sub->interface_name, (char *)s,
785 vec_len(sub->interface_name));
786 sub->sw_if_index = ntohl(mp->sw_if_index);
787 sub->sub_id = ntohl(mp->sub_id);
788
789 sub->sub_dot1ad = mp->sub_dot1ad;
790 sub->sub_number_of_tags = mp->sub_number_of_tags;
791 sub->sub_outer_vlan_id = ntohs(mp->sub_outer_vlan_id);
792 sub->sub_inner_vlan_id = ntohs(mp->sub_inner_vlan_id);
793 sub->sub_exact_match = mp->sub_exact_match;
794 sub->sub_default = mp->sub_default;
795 sub->sub_outer_vlan_id_any = mp->sub_outer_vlan_id_any;
796 sub->sub_inner_vlan_id_any = mp->sub_inner_vlan_id_any;
797
798 /* vlan tag rewrite */
799 sub->vtr_op = ntohl(mp->vtr_op);
800 sub->vtr_push_dot1q = ntohl(mp->vtr_push_dot1q);
801 sub->vtr_tag1 = ntohl(mp->vtr_tag1);
802 sub->vtr_tag2 = ntohl(mp->vtr_tag2);
803 }
804 vppjni_unlock (jm);
805}
806
807static void vl_api_sw_interface_set_flags_t_handler
808(vl_api_sw_interface_set_flags_t * mp)
809{
810 /* $$$ nothing for the moment */
811}
812
813static jintArray create_array_of_bd_ids(JNIEnv * env, jint bd_id)
814{
815 vppjni_main_t *jm = &vppjni_main;
816 vjbd_main_t * bdm = &jm->vjbd_main;
817 u32 *buf = NULL;
818 u32 i;
819
820 if (bd_id != ~0) {
821 vec_add1(buf, bd_id);
822 } else {
823 for (i = 0; i < vec_len(bdm->bd_oper); i++) {
824 u32 bd_id = bdm->bd_oper[i].bd_id;
825 vec_add1(buf, bd_id);
826 }
827 }
828
829 jintArray bdidArray = (*env)->NewIntArray(env, vec_len(buf));
830
831 (*env)->SetIntArrayRegion(env, bdidArray, 0, vec_len(buf), (int*)buf);
832
833 return bdidArray;
834}
835
836static void bridge_domain_oper_free(void)
837{
838 vppjni_main_t *jm = &vppjni_main;
839 vjbd_main_t *bdm = &jm->vjbd_main;
840 u32 i;
841
842 for (i = 0; i < vec_len(bdm->bd_oper); i++) {
843 vec_free(bdm->bd_oper->l2fib_oper);
844 }
845 vec_reset_length(bdm->bd_oper);
846 hash_free(bdm->bd_id_by_sw_if_index);
847 hash_free(bdm->oper_bd_index_by_bd_id);
848}
849
850JNIEXPORT jintArray JNICALL Java_org_openvpp_vppjapi_vppConn_bridgeDomainDump
851(JNIEnv * env, jobject obj, jint bd_id)
852{
853 vppjni_main_t *jm = &vppjni_main;
854 vl_api_bridge_domain_dump_t * mp;
855 u32 my_context_id;
856 f64 timeout;
857 int rv;
858 rv = vppjni_sanity_check (jm);
859 if (rv) return NULL;
860
861 vppjni_lock (jm, 15);
862
863 if (~0 == bd_id) {
864 bridge_domain_oper_free();
865 }
866
867 my_context_id = vppjni_get_context_id (jm);
868 M(BRIDGE_DOMAIN_DUMP, bridge_domain_dump);
869 mp->context = clib_host_to_net_u32 (my_context_id);
870 mp->bd_id = clib_host_to_net_u32(bd_id);
871 S;
872
873 /* Use a control ping for synchronization */
874 {
875 vl_api_control_ping_t * mp;
876 M(CONTROL_PING, control_ping);
877 S;
878 }
879
880 WNR;
881 if (0 != rv) {
882 return NULL;
883 }
884
885 jintArray ret = create_array_of_bd_ids(env, bd_id);
886
887 vppjni_unlock (jm);
888
889 return ret;
890}
891
892static void
893vl_api_bridge_domain_details_t_handler (vl_api_bridge_domain_details_t * mp)
894{
895 vppjni_main_t *jm = &vppjni_main;
896 vjbd_main_t * bdm = &jm->vjbd_main;
897 vjbd_oper_t * bd_oper;
898 u32 bd_id, bd_index;
899
900 bd_id = ntohl (mp->bd_id);
901
902 bd_index = vec_len(bdm->bd_oper);
903 vec_validate (bdm->bd_oper, bd_index);
904 bd_oper = vec_elt_at_index(bdm->bd_oper, bd_index);
905
906 hash_set(bdm->oper_bd_index_by_bd_id, bd_id, bd_index);
907
908 bd_oper->bd_id = bd_id;
909 bd_oper->flood = mp->flood != 0;
910 bd_oper->forward = mp->forward != 0;
911 bd_oper->learn = mp->learn != 0;
912 bd_oper->uu_flood = mp->flood != 0;
913 bd_oper->arp_term = mp->arp_term != 0;
914 bd_oper->bvi_sw_if_index = ntohl (mp->bvi_sw_if_index);
915 bd_oper->n_sw_ifs = ntohl (mp->n_sw_ifs);
916
917 bd_oper->bd_sw_if_oper = 0;
918}
919
920static void
921vl_api_bridge_domain_sw_if_details_t_handler
922(vl_api_bridge_domain_sw_if_details_t * mp)
923{
924 vppjni_main_t *jm = &vppjni_main;
925 vjbd_main_t * bdm = &jm->vjbd_main;
926 bd_sw_if_oper_t * bd_sw_if_oper;
927 u32 bd_id, sw_if_index;
928
929 bd_id = ntohl (mp->bd_id);
930 sw_if_index = ntohl (mp->sw_if_index);
931
932 uword *p;
933 p = hash_get (bdm->oper_bd_index_by_bd_id, bd_id);
934 if (p == 0) {
935 clib_warning("Invalid bd_id %d in bridge_domain_sw_if_details_t_handler", bd_id);
936 return;
937 }
938 u32 oper_bd_index = (jint) p[0];
939 vjbd_oper_t *bd_oper = vec_elt_at_index(bdm->bd_oper, oper_bd_index);
940
941 u32 len = vec_len(bd_oper->bd_sw_if_oper);
942 vec_validate(bd_oper->bd_sw_if_oper, len);
943 bd_sw_if_oper = &bd_oper->bd_sw_if_oper[len];
944 bd_sw_if_oper->bd_id = bd_id;
945 bd_sw_if_oper->sw_if_index = sw_if_index;
946 bd_sw_if_oper->shg = mp->shg;
947
948 hash_set(bdm->bd_id_by_sw_if_index, sw_if_index, bd_id);
949}
950
951static const char* interface_name_from_sw_if_index(u32 sw_if_index)
952{
953 vppjni_main_t *jm = &vppjni_main;
954
955 if (sw_if_index >= vec_len(jm->sw_if_table)) {
956 return NULL;
957 }
958 if (!jm->sw_if_table[sw_if_index].valid) {
959 return NULL;
960 }
961 return (const char*)jm->sw_if_table[sw_if_index].interface_name;
962}
963
964JNIEXPORT jobject JNICALL Java_org_openvpp_vppjapi_vppConn_getBridgeDomainDetails
965(JNIEnv * env, jobject obj, jint bdId)
966{
967 vppjni_main_t *jm = &vppjni_main;
968 vjbd_main_t * bdm = &jm->vjbd_main;
969 u32 oper_bd_index;
970 u32 bd_id = bdId;
971 jobject rv = NULL;
972 uword *p;
973
974 vppjni_lock (jm, 16);
975
976 p = hash_get (bdm->oper_bd_index_by_bd_id, bd_id);
977 if (p == 0) {
978 rv = NULL;
979 goto out;
980 }
981 oper_bd_index = (jint) p[0];
982
983 vjbd_oper_t *bd_oper = vec_elt_at_index(bdm->bd_oper, oper_bd_index);
984
985
986 /* setting BridgeDomainDetails */
987
988 jclass bddClass = (*env)->FindClass(env, "org/openvpp/vppjapi/vppBridgeDomainDetails");
989 if ((*env)->ExceptionCheck(env)) {
990 (*env)->ExceptionDescribe(env);
991 rv = NULL;
992 goto out;
993 }
994
995 jmethodID midInit = (*env)->GetMethodID(env, bddClass, "<init>", "()V");
996 if ((*env)->ExceptionCheck(env)) {
997 (*env)->ExceptionDescribe(env);
998 rv = NULL;
999 goto out;
1000 }
1001 jobject bddObj = (*env)->NewObject(env, bddClass, midInit);
1002
1003 u8 *vec_bd_name = vjbd_oper_name_from_id(bdm, bd_id);
1004 if (NULL == vec_bd_name) {
1005 rv = NULL;
1006 goto out;
1007 }
1008 char *str_bd_name = (char*)format (0, "%s%c", vec_bd_name, 0);
1009 vec_free(vec_bd_name);
1010 jstring bdName = (*env)->NewStringUTF(env, str_bd_name);
1011 vec_free(str_bd_name);
1012 if (NULL == bdName) {
1013 rv = NULL;
1014 goto out;
1015 }
1016 jfieldID fidName = (*env)->GetFieldID(env, bddClass, "name", "Ljava/lang/String;");
1017 if ((*env)->ExceptionCheck(env)) {
1018 (*env)->ExceptionDescribe(env);
1019 rv = NULL;
1020 goto out;
1021 }
1022 (*env)->SetObjectField(env, bddObj, fidName, bdName);
1023
1024 jfieldID fidBdId = (*env)->GetFieldID(env, bddClass, "bdId", "I");
1025 if ((*env)->ExceptionCheck(env)) {
1026 (*env)->ExceptionDescribe(env);
1027 rv = NULL;
1028 goto out;
1029 }
1030 (*env)->SetIntField(env, bddObj, fidBdId, bdId);
1031
1032 jboolean flood = bd_oper->flood;
1033 jfieldID fidFlood = (*env)->GetFieldID(env, bddClass, "flood", "Z");
1034 if ((*env)->ExceptionCheck(env)) {
1035 (*env)->ExceptionDescribe(env);
1036 rv = NULL;
1037 goto out;
1038 }
1039 (*env)->SetBooleanField(env, bddObj, fidFlood, flood);
1040
1041 jboolean uuFlood = bd_oper->uu_flood;
1042 jfieldID fidUuFlood = (*env)->GetFieldID(env, bddClass, "uuFlood", "Z");
1043 if ((*env)->ExceptionCheck(env)) {
1044 (*env)->ExceptionDescribe(env);
1045 rv = NULL;
1046 goto out;
1047 }
1048 (*env)->SetBooleanField(env, bddObj, fidUuFlood, uuFlood);
1049
1050 jboolean forward = bd_oper->forward;
1051 jfieldID fidForward = (*env)->GetFieldID(env, bddClass, "forward", "Z");
1052 if ((*env)->ExceptionCheck(env)) {
1053 (*env)->ExceptionDescribe(env);
1054 rv = NULL;
1055 goto out;
1056 }
1057 (*env)->SetBooleanField(env, bddObj, fidForward, forward);
1058
1059 jboolean learn = bd_oper->learn;
1060 jfieldID fidLearn = (*env)->GetFieldID(env, bddClass, "learn", "Z");
1061 if ((*env)->ExceptionCheck(env)) {
1062 (*env)->ExceptionDescribe(env);
1063 rv = NULL;
1064 goto out;
1065 }
1066 (*env)->SetBooleanField(env, bddObj, fidLearn, learn);
1067
1068 jboolean arpTerm = bd_oper->arp_term;
1069 jfieldID fidArpTerm = (*env)->GetFieldID(env, bddClass, "arpTerm", "Z");
1070 if ((*env)->ExceptionCheck(env)) {
1071 (*env)->ExceptionDescribe(env);
1072 rv = NULL;
1073 goto out;
1074 }
1075 (*env)->SetBooleanField(env, bddObj, fidArpTerm, arpTerm);
1076
1077 jstring bviInterfaceName = NULL;
1078 if (~0 != bd_oper->bvi_sw_if_index) {
1079 const char *str_if_name = interface_name_from_sw_if_index(bd_oper->bvi_sw_if_index);
1080 if (NULL == str_if_name) {
1081 clib_warning("Could not get interface name for sw_if_index %d", bd_oper->bvi_sw_if_index);
1082 rv = NULL;
1083 goto out;
1084 }
1085 bviInterfaceName = (*env)->NewStringUTF(env, str_if_name);
1086 if (NULL == bviInterfaceName) {
1087 rv = NULL;
1088 goto out;
1089 }
1090 }
1091 jfieldID fidBviInterfaceName = (*env)->GetFieldID(env, bddClass, "bviInterfaceName", "Ljava/lang/String;");
1092 if ((*env)->ExceptionCheck(env)) {
1093 (*env)->ExceptionDescribe(env);
1094 rv = NULL;
1095 goto out;
1096 }
1097 (*env)->SetObjectField(env, bddObj, fidBviInterfaceName, bviInterfaceName);
1098
1099
1100 /* setting BridgeDomainInterfaceDetails */
1101
1102 jclass bdidClass = (*env)->FindClass(env, "org/openvpp/vppjapi/vppBridgeDomainInterfaceDetails");
1103 if ((*env)->ExceptionCheck(env)) {
1104 (*env)->ExceptionDescribe(env);
1105 rv = NULL;
1106 goto out;
1107 }
1108
1109 jfieldID fidInterfaceName = (*env)->GetFieldID(env, bdidClass, "interfaceName", "Ljava/lang/String;");
1110 if ((*env)->ExceptionCheck(env)) {
1111 (*env)->ExceptionDescribe(env);
1112 rv = NULL;
1113 goto out;
1114 }
1115
1116 jfieldID fidSHG = (*env)->GetFieldID(env, bdidClass, "splitHorizonGroup", "B");
1117 if ((*env)->ExceptionCheck(env)) {
1118 (*env)->ExceptionDescribe(env);
1119 rv = NULL;
1120 goto out;
1121 }
1122
1123 u32 len = vec_len(bd_oper->bd_sw_if_oper);
1124 ASSERT(len == bd_oper->n_sw_ifs);
1125
1126 jobjectArray bdidArray = (*env)->NewObjectArray(env, len, bdidClass, NULL);
1127
1128 u32 i;
1129 for (i = 0; i < len; i++) {
1130 bd_sw_if_oper_t *sw_if_oper = &bd_oper->bd_sw_if_oper[i];
1131
1132 jmethodID midBdidInit = (*env)->GetMethodID(env, bdidClass, "<init>", "()V");
1133 if ((*env)->ExceptionCheck(env)) {
1134 (*env)->ExceptionDescribe(env);
1135 rv = NULL;
1136 goto out;
1137 }
1138 jobject bdidObj = (*env)->NewObject(env, bdidClass, midBdidInit);
1139 (*env)->SetObjectArrayElement(env, bdidArray, i, bdidObj);
1140
1141 u32 sw_if_index = sw_if_oper->sw_if_index;
1142 const char *str_if_name = interface_name_from_sw_if_index(sw_if_index);
1143 if (NULL == str_if_name) {
1144 rv = NULL;
1145 goto out;
1146 }
1147 jstring interfaceName = (*env)->NewStringUTF(env, str_if_name);
1148 if (NULL == interfaceName) {
1149 rv = NULL;
1150 goto out;
1151 }
1152 (*env)->SetObjectField(env, bdidObj, fidInterfaceName, interfaceName);
1153
1154 jbyte shg = sw_if_oper->shg;
1155 (*env)->SetByteField(env, bdidObj, fidSHG, shg);
1156 }
1157
1158 jfieldID fidInterfaces = (*env)->GetFieldID(env, bddClass, "interfaces",
1159 "[Lorg/openvpp/vppjapi/vppBridgeDomainInterfaceDetails;");
1160 if ((*env)->ExceptionCheck(env)) {
1161 (*env)->ExceptionDescribe(env);
1162 rv = NULL;
1163 goto out;
1164 }
1165 (*env)->SetObjectField(env, bddObj, fidInterfaces, bdidArray);
1166
1167 rv = bddObj;
1168
1169out:
1170
1171 vppjni_unlock (jm);
1172
1173 return rv;
1174}
1175
1176static jobject l2_fib_create_object(JNIEnv *env, bd_l2fib_oper_t *l2_fib)
1177{
1178 jclass l2FibClass = (*env)->FindClass(env, "org/openvpp/vppjapi/vppL2Fib");
1179 if ((*env)->ExceptionCheck(env)) {
1180 (*env)->ExceptionDescribe(env);
1181 return NULL;
1182 }
1183
1184 jmethodID midL2FIbInit = (*env)->GetMethodID(env, l2FibClass, "<init>", "([BZLjava/lang/String;ZZ)V");
1185 if ((*env)->ExceptionCheck(env)) {
1186 (*env)->ExceptionDescribe(env);
1187 return NULL;
1188 }
1189
1190 u32 sw_if_index = l2_fib->sw_if_index;
1191 const char *str_if_name = interface_name_from_sw_if_index(sw_if_index);
1192 if (NULL == str_if_name) {
1193 return NULL;
1194 }
1195 jstring interfaceName = (*env)->NewStringUTF(env, str_if_name);
1196 if (NULL == interfaceName) {
1197 return NULL;
1198 }
1199
1200 jbyteArray physAddr = (*env)->NewByteArray(env, 6);
1201 (*env)->SetByteArrayRegion(env, physAddr, 0, 6,
1202 (signed char*)l2_fib->mac_addr.fields.mac);
1203 jboolean staticConfig = !l2_fib->learned;
1204 jstring outgoingInterface = interfaceName;
1205 jboolean filter = l2_fib->filter;
1206 jboolean bridgedVirtualInterface = l2_fib->bvi;
1207
1208 jobject l2FibObj = (*env)->NewObject(env, l2FibClass, midL2FIbInit,
1209 physAddr, staticConfig, outgoingInterface, filter,
1210 bridgedVirtualInterface);
1211
1212 return l2FibObj;
1213}
1214
1215JNIEXPORT jobjectArray JNICALL Java_org_openvpp_vppjapi_vppConn_l2FibTableDump
1216(JNIEnv * env, jobject obj, jint bd_id)
1217{
1218 vppjni_main_t *jm = &vppjni_main;
1219 vjbd_main_t * bdm = &jm->vjbd_main;
1220 vl_api_l2_fib_table_dump_t *mp;
1221 jobjectArray l2FibArray = NULL;
1222 vjbd_oper_t *bd_oper;
1223 u32 oper_bd_index;
1224 uword *p;
1225 f64 timeout;
1226 int rv;
1227 u32 i;
1228
1229 vppjni_lock (jm, 17);
1230
1231 //vjbd_l2fib_oper_reset (bdm);
1232
1233 p = hash_get (bdm->oper_bd_index_by_bd_id, bd_id);
1234 if (p == 0) {
1235 goto done;
1236 }
1237 oper_bd_index = p[0];
1238 bd_oper = vec_elt_at_index(bdm->bd_oper, oper_bd_index);
1239 vec_reset_length (bd_oper->l2fib_oper);
1240
1241 /* Get list of l2 fib table entries */
1242 M(L2_FIB_TABLE_DUMP, l2_fib_table_dump);
1243 mp->bd_id = ntohl(bd_id);
1244 S;
1245
1246 /* Use a control ping for synchronization */
1247 {
1248 vl_api_control_ping_t * mp;
1249 M(CONTROL_PING, control_ping);
1250 S;
1251 }
1252
1253 WNR;
1254 if (0 != rv) {
1255 goto done;
1256 }
1257
1258 u32 count = vec_len(bd_oper->l2fib_oper);
1259 bd_l2fib_oper_t *l2fib_oper = bd_oper->l2fib_oper;
1260
1261 jclass l2FibClass = (*env)->FindClass(env, "org/openvpp/vppjapi/vppL2Fib");
1262 if ((*env)->ExceptionCheck(env)) {
1263 (*env)->ExceptionDescribe(env);
1264 goto done;
1265 }
1266
1267 l2FibArray = (*env)->NewObjectArray(env, count, l2FibClass, NULL);
1268
1269 u32 pos = 0;
1270 for (i = 0; i < count; i++) {
1271 bd_l2fib_oper_t *l2_fib = &l2fib_oper[i];
1272 if (1) {
1273 jobject l2FibObj = l2_fib_create_object(env, l2_fib);
1274 (*env)->SetObjectArrayElement(env, l2FibArray, pos, l2FibObj);
1275 pos++;
1276 }
1277 }
1278
1279done:
1280 vppjni_unlock (jm);
1281
1282 return l2FibArray;
1283}
1284
1285static void
1286vl_api_l2_fib_table_entry_t_handler (vl_api_l2_fib_table_entry_t * mp)
1287{
1288 //static u8 * mac_addr;
1289 vppjni_main_t *jm = &vppjni_main;
1290 vjbd_main_t * bdm = &jm->vjbd_main;
1291 vjbd_oper_t * bd_oper;
1292 u32 bd_id, oper_bd_index;
1293 //uword mhash_val_l2fi;
1294 bd_l2fib_oper_t * l2fib_oper;
1295 l2fib_u64_mac_t * l2fe_u64_mac = (l2fib_u64_mac_t *)&mp->mac;
1296
1297 bd_id = ntohl (mp->bd_id);
1298
1299 uword *p = hash_get (bdm->oper_bd_index_by_bd_id, bd_id);
1300 if (p == 0) {
1301 return;
1302 }
1303 oper_bd_index = (jint) p[0];
1304 bd_oper = vec_elt_at_index(bdm->bd_oper, oper_bd_index);
1305
1306#if 0
1307 vec_validate (mac_addr, MAC_ADDRESS_SIZE);
1308 memcpy (mac_addr, l2fe_u64_mac->fields.mac, MAC_ADDRESS_SIZE);
1309 mhash_val_l2fi = vec_len (bd_oper->l2fib_oper);
1310 if (mhash_elts (&bd_oper->l2fib_index_by_mac) == 0)
1311 mhash_init (&bd_oper->l2fib_index_by_mac, sizeof (u32), MAC_ADDRESS_SIZE);
1312 mhash_set_mem (&bd_oper->l2fib_index_by_mac, mac_addr, &mhash_val_l2fi, 0);
1313#endif
1314
1315 vec_add2 (bd_oper->l2fib_oper, l2fib_oper, 1);
1316
1317 l2fib_oper->bd_id = bd_id;
1318 l2fib_oper->mac_addr.raw = l2fib_mac_to_u64 (l2fe_u64_mac->fields.mac);
1319 l2fib_oper->sw_if_index = ntohl (mp->sw_if_index);
1320 l2fib_oper->learned = !mp->static_mac;
1321 l2fib_oper->filter = mp->filter_mac;
1322 l2fib_oper->bvi = mp->bvi_mac;
1323}
1324
1325/* cleanup handler for RX thread */
1326void cleanup_rx_thread(void *arg)
1327{
1328 vppjni_main_t * jm = &vppjni_main;
1329
1330 vppjni_lock (jm, 99);
1331
1332 int getEnvStat = (*jm->jvm)->GetEnv(jm->jvm, (void **)&(jm->jenv), JNI_VERSION_1_6);
1333 if (getEnvStat == JNI_EVERSION) {
1334 clib_warning ("Unsupported JNI version\n");
1335 jm->retval = -999;
1336 goto out;
1337 } else if (getEnvStat != JNI_EDETACHED) {
1338 (*jm->jvm)->DetachCurrentThread(jm->jvm);
1339 }
1340out:
1341 vppjni_unlock (jm);
1342}
1343
1344static void
1345vl_api_show_version_reply_t_handler (vl_api_show_version_reply_t * mp)
1346{
1347 vppjni_main_t * jm = &vppjni_main;
1348 i32 retval = ntohl(mp->retval);
1349
1350 if (retval >= 0) {
1351 clib_warning ("show version request succeeded(%d)");
1352 strncpy((char*)jm->program_name, (const char*)mp->program,
1353 sizeof(jm->program_name)-1);
1354 jm->program_name[sizeof(jm->program_name)-1] = 0;
1355
1356 strncpy((char*)jm->build_directory, (const char*)mp->build_directory,
1357 sizeof(jm->build_directory)-1);
1358 jm->build_directory[sizeof(jm->build_directory)-1] = 0;
1359
Damjan Mariona0d4a1a2015-12-12 14:40:59 +01001360 strncpy((char*)jm->version, (const char*)mp->version,
1361 sizeof(jm->version)-1);
1362 jm->version[sizeof(jm->version)-1] = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001363
1364 strncpy((char*)jm->build_date, (const char*)mp->build_date,
1365 sizeof(jm->build_date)-1);
1366 jm->build_date[sizeof(jm->build_date)-1] = 0;
1367 } else {
1368 clib_error ("show version request failed(%d)", retval);
1369 }
1370 jm->retval = retval;
1371 jm->result_ready = 1;
1372}
1373
1374static void vl_api_want_stats_reply_t_handler (vl_api_want_stats_reply_t * mp)
1375{
1376 vppjni_main_t * jm = &vppjni_main;
1377 jm->retval = mp->retval; // FIXME: vpp api does not do ntohl on this retval
1378 jm->result_ready = 1;
1379}
1380
1381// control ping needs to be very first thing called
1382// to attach rx thread to java thread
1383static void vl_api_control_ping_reply_t_handler
1384(vl_api_control_ping_reply_t * mp)
1385{
1386 vppjni_main_t * jm = &vppjni_main;
1387 i32 retval = ntohl(mp->retval);
1388 u32 context = clib_host_to_net_u32 (mp->context);
1389 uword *p = NULL;
1390
1391 jm->retval = retval;
1392
1393 // attach to java thread if not attached
1394 int getEnvStat = (*jm->jvm)->GetEnv(jm->jvm, (void **)&(jm->jenv), JNI_VERSION_1_6);
1395 if (getEnvStat == JNI_EDETACHED) {
1396 if ((*jm->jvm)->AttachCurrentThread(jm->jvm, (void **)&(jm->jenv), NULL) != 0) {
1397 clib_warning("Failed to attach thread\n");
1398 jm->retval = -999;
1399 goto out;
1400 }
1401
1402 // workaround as we can't use pthread_cleanup_push
1403 pthread_key_create(&jm->cleanup_rx_thread_key, cleanup_rx_thread);
1404 // destructor is only called if the value of key is non null
1405 pthread_setspecific(jm->cleanup_rx_thread_key, (void *)1);
1406 } else if (getEnvStat == JNI_EVERSION) {
1407 clib_warning ("Unsupported JNI version\n");
1408 jm->retval = -999;
1409 goto out;
1410 }
1411 // jm->jenv is now stable global reference that can be reused
1412
1413 // get issuer msg-id
1414 p = hash_get (jm->ping_hash, context);
1415 if (p != 0) { // ping marks end of some dump call
1416 JNIEnv *env = jm->jenv;
1417 u16 msg_id = (u16)p[0];
1418
1419 // we will no longer need this
1420 hash_unset (jm->ping_hash, context);
1421
1422 // get original caller obj
1423 p = hash_get (jm->callback_hash, context);
1424
1425 if (p == 0) // don't have callback stored
1426 goto out;
1427
1428 jobject obj = (jobject)p[0]; // object that called original call
1429
1430 switch (msg_id) {
1431 case VL_API_SW_INTERFACE_DUMP:
1432 if (0 != sw_if_dump_call_all_callbacks(obj)) {
1433 goto out2;
1434 }
1435 break;
1436 default:
1437 clib_warning("Unhandled control ping issuer msg-id: %d", msg_id);
1438 goto out2;
1439 break;
1440 }
1441 out2:
1442 // free the saved obj
1443 hash_unset (jm->callback_hash, context);
1444 // delete global reference
1445 (*env)->DeleteGlobalRef(env, obj);
1446 }
1447out:
1448 jm->result_ready = 1;
1449}
1450
1451#define VPPJNI_DEBUG_COUNTERS 0
1452
1453static void vl_api_vnet_interface_counters_t_handler
1454(vl_api_vnet_interface_counters_t *mp)
1455{
1456 vppjni_main_t *jm = &vppjni_main;
1457 CLIB_UNUSED(char *counter_name);
1458 u32 count, sw_if_index;
1459 int i;
1460 static sw_interface_stats_t empty_stats = {0, };
1461
1462 vppjni_lock (jm, 12);
1463 count = ntohl (mp->count);
1464 sw_if_index = ntohl (mp->first_sw_if_index);
1465 if (mp->is_combined == 0) {
1466 u64 * vp, v;
1467 vp = (u64 *) mp->data;
1468
1469 for (i = 0; i < count; i++) {
1470 sw_interface_details_t *sw_if = NULL;
1471
1472 v = clib_mem_unaligned (vp, u64);
1473 v = clib_net_to_host_u64 (v);
1474 vp++;
1475
1476 if (sw_if_index < vec_len(jm->sw_if_table))
1477 sw_if = vec_elt_at_index(jm->sw_if_table, sw_if_index);
1478
1479 if (sw_if /* && (sw_if->admin_up_down == 1)*/ && sw_if->interface_name[0] != 0)
1480 {
1481 vec_validate_init_empty(jm->sw_if_stats_by_sw_if_index, sw_if_index, empty_stats);
1482 sw_interface_stats_t * s = vec_elt_at_index(jm->sw_if_stats_by_sw_if_index, sw_if_index);
1483
1484 s->sw_if_index = sw_if_index;
1485 s->valid = 1;
1486
1487 switch (mp->vnet_counter_type) {
1488 case VNET_INTERFACE_COUNTER_DROP:
1489 counter_name = "drop";
1490 s->rx.pkts.discard = v;
1491 break;
1492 case VNET_INTERFACE_COUNTER_PUNT:
1493 counter_name = "punt";
1494 s->rx.pkts.unknown_proto = v;
1495 break;
1496 case VNET_INTERFACE_COUNTER_IP4:
1497 counter_name = "ip4";
1498 s->rx.pkts.ip4 = v;
1499 break;
1500 case VNET_INTERFACE_COUNTER_IP6:
1501 counter_name = "ip6";
1502 s->rx.pkts.ip6 = v;
1503 break;
1504 case VNET_INTERFACE_COUNTER_RX_NO_BUF:
1505 counter_name = "rx-no-buf";
1506 s->rx.pkts.fifo_full = v;
1507 break;
1508 case VNET_INTERFACE_COUNTER_RX_MISS:
1509 counter_name = "rx-miss";
1510 s->rx.pkts.miss = v;
1511 break;
1512 case VNET_INTERFACE_COUNTER_RX_ERROR:
1513 counter_name = "rx-error";
1514 s->rx.pkts.error = v;
1515 break;
1516 case VNET_INTERFACE_COUNTER_TX_ERROR:
1517 counter_name = "tx-error (fifo-full)";
1518 s->tx.pkts.fifo_full = v;
1519 break;
1520 default:
1521 counter_name = "bogus";
1522 break;
1523 }
1524
1525#if VPPJNI_DEBUG_COUNTERS == 1
1526 clib_warning ("%s (%d): %s (%lld)\n", sw_if->interface_name, s->sw_if_index,
1527 counter_name, v);
1528#endif
1529 }
1530 sw_if_index++;
1531 }
1532 } else {
1533 vlib_counter_t *vp;
1534 u64 packets, bytes;
1535 vp = (vlib_counter_t *) mp->data;
1536
1537 for (i = 0; i < count; i++) {
1538 sw_interface_details_t *sw_if = NULL;
1539
1540 packets = clib_mem_unaligned (&vp->packets, u64);
1541 packets = clib_net_to_host_u64 (packets);
1542 bytes = clib_mem_unaligned (&vp->bytes, u64);
1543 bytes = clib_net_to_host_u64 (bytes);
1544 vp++;
1545
1546 if (sw_if_index < vec_len(jm->sw_if_table))
1547 sw_if = vec_elt_at_index(jm->sw_if_table, sw_if_index);
1548
1549 if (sw_if /* && (sw_if->admin_up_down == 1) */ && sw_if->interface_name[0] != 0)
1550 {
1551 vec_validate_init_empty(jm->sw_if_stats_by_sw_if_index, sw_if_index, empty_stats);
1552 sw_interface_stats_t * s = vec_elt_at_index(jm->sw_if_stats_by_sw_if_index, sw_if_index);
1553
1554 s->valid = 1;
1555 s->sw_if_index = sw_if_index;
1556
1557 switch (mp->vnet_counter_type) {
1558 case VNET_INTERFACE_COUNTER_RX:
1559 s->rx.pkts.unicast = packets;
1560 s->rx.octets = bytes;
1561 counter_name = "rx";
1562 break;
1563
1564 case VNET_INTERFACE_COUNTER_TX:
1565 s->tx.pkts.unicast = packets;
1566 s->tx.octets = bytes;
1567 counter_name = "tx";
1568 break;
1569
1570 default:
1571 counter_name = "bogus";
1572 break;
1573 }
1574
1575#if VPPJNI_DEBUG_COUNTERS == 1
1576 clib_warning ("%s (%d): %s.packets %lld\n",
1577 sw_if->interface_name,
1578 sw_if_index, counter_name, packets);
1579 clib_warning ("%s (%d): %s.bytes %lld\n",
1580 sw_if->interface_name,
1581 sw_if_index, counter_name, bytes);
1582#endif
1583 }
1584 sw_if_index++;
1585 }
1586 }
1587 vppjni_unlock (jm);
1588}
1589
1590jint JNI_OnLoad(JavaVM *vm, void *reserved) {
1591 vppjni_main_t * jm = &vppjni_main;
1592 JNIEnv* env;
1593 if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) {
1594 return JNI_ERR;
1595 }
1596
1597 jclass cls = (*env)->FindClass(env, "org/openvpp/vppjapi/vppApiCallbacks");
1598 if ((*env)->ExceptionCheck(env)) {
1599 (*env)->ExceptionDescribe(env);
1600 return JNI_ERR;
1601 }
1602
1603 jm->jmtdIfDetails =
1604 (*env)->GetMethodID(env, cls, "interfaceDetails", "(ILjava/lang/String;I[BBBBBIBBIIBBBBIIII)V");
1605 if ((*env)->ExceptionCheck(env)) {
1606 (*env)->ExceptionDescribe(env);
1607 return JNI_ERR;
1608 }
1609
1610 // methods are not local references they stay forever
1611 // jclass is local reference let's hold global ref to it
1612 jm->jcls = (*env)->NewGlobalRef(env, cls);
1613
1614 jm->jvm = vm;
1615 return JNI_VERSION_1_6;
1616}
1617
1618void JNI_OnUnload(JavaVM *vm, void *reserved) {
1619 vppjni_main_t * jm = &vppjni_main;
1620 JNIEnv* env;
1621 if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) {
1622 return;
1623 }
1624
1625 if (jm->jcls != NULL) {
1626 (*env)->DeleteGlobalRef(env, jm->jcls);
1627 jm->jcls = NULL;
1628 }
1629
1630 jm->jenv = NULL;
1631 jm->jvm = NULL;
1632}
1633
1634#define foreach_vpe_api_msg \
1635_(CONTROL_PING_REPLY, control_ping_reply) \
1636_(SW_INTERFACE_DETAILS, sw_interface_details) \
1637_(SHOW_VERSION_REPLY, show_version_reply) \
1638_(WANT_STATS_REPLY, want_stats_reply) \
1639_(VNET_INTERFACE_COUNTERS, vnet_interface_counters) \
1640_(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags) \
1641_(BRIDGE_DOMAIN_DETAILS, bridge_domain_details) \
1642_(BRIDGE_DOMAIN_SW_IF_DETAILS, bridge_domain_sw_if_details) \
1643_(L2_FIB_TABLE_ENTRY, l2_fib_table_entry)
1644
1645static int connect_to_vpe(char *name)
1646{
1647 vppjni_main_t * jm = &vppjni_main;
1648 api_main_t * am = &api_main;
1649
1650 if (vl_client_connect_to_vlib("/vpe-api", name, 32) < 0)
1651 return -1;
1652
1653 jm->my_client_index = am->my_client_index;
1654 jm->vl_input_queue = am->shmem_hdr->vl_input_queue;
1655
1656#define _(N,n) \
1657 vl_msg_api_set_handlers(VL_API_##N, #n, \
1658 vl_api_##n##_t_handler, \
1659 vl_noop_handler, \
1660 vl_api_##n##_t_endian, \
1661 vl_api_##n##_t_print, \
1662 sizeof(vl_api_##n##_t), 1);
1663 foreach_vpe_api_msg;
1664#undef _
1665
1666
1667 return 0;
1668}
1669
1670/* Format an IP6 address. */
1671u8 * format_ip6_address (u8 * s, va_list * args)
1672{
1673 ip6_address_t * a = va_arg (*args, ip6_address_t *);
1674 u32 max_zero_run = 0, this_zero_run = 0;
1675 int max_zero_run_index = -1, this_zero_run_index=0;
1676 int in_zero_run = 0, i;
1677 int last_double_colon = 0;
1678
1679 /* Ugh, this is a pain. Scan forward looking for runs of 0's */
1680 for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
1681 {
1682 if (a->as_u16[i] == 0)
1683 {
1684 if (in_zero_run)
1685 this_zero_run++;
1686 else
1687 {
1688 in_zero_run = 1;
1689 this_zero_run =1;
1690 this_zero_run_index = i;
1691 }
1692 }
1693 else
1694 {
1695 if (in_zero_run)
1696 {
1697 /* offer to compress the biggest run of > 1 zero */
1698 if (this_zero_run > max_zero_run && this_zero_run > 1)
1699 {
1700 max_zero_run_index = this_zero_run_index;
1701 max_zero_run = this_zero_run;
1702 }
1703 }
1704 in_zero_run = 0;
1705 this_zero_run = 0;
1706 }
1707 }
1708
1709 if (in_zero_run)
1710 {
1711 if (this_zero_run > max_zero_run && this_zero_run > 1)
1712 {
1713 max_zero_run_index = this_zero_run_index;
1714 max_zero_run = this_zero_run;
1715 }
1716 }
1717
1718 for (i = 0; i < ARRAY_LEN (a->as_u16); i++)
1719 {
1720 if (i == max_zero_run_index)
1721 {
1722 s = format (s, "::");
1723 i += max_zero_run - 1;
1724 last_double_colon = 1;
1725 }
1726 else
1727 {
1728 s = format (s, "%s%x",
1729 (last_double_colon || i == 0) ? "" : ":",
1730 clib_net_to_host_u16 (a->as_u16[i]));
1731 last_double_colon = 0;
1732 }
1733 }
1734
1735 return s;
1736}
1737
1738/* Format an IP4 address. */
1739u8 * format_ip4_address (u8 * s, va_list * args)
1740{
1741 u8 * a = va_arg (*args, u8 *);
1742 return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
1743}
1744
1745