vcl: add read/write udp support
[vpp.git] / src / vcl / vcl_bapi.c
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this
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
16 #include <vcl/vcl_private.h>
17 #include <vlibmemory/api.h>
18 #include <vpp/api/vpe_msg_enum.h>
19
20 #define vl_typedefs             /* define message structures */
21 #include <vpp/api/vpe_all_api_h.h>
22 #undef vl_typedefs
23
24 /* declare message handlers for each api */
25
26 #define vl_endianfun            /* define message structures */
27 #include <vpp/api/vpe_all_api_h.h>
28 #undef vl_endianfun
29
30 /* instantiate all the print functions we know about */
31 #define vl_print(handle, ...)
32 #define vl_printfun
33 #include <vpp/api/vpe_all_api_h.h>
34 #undef vl_printfun
35
36 u8 *
37 format_api_error (u8 * s, va_list * args)
38 {
39   i32 error = va_arg (*args, u32);
40   uword *p;
41
42   p = hash_get (vcm->error_string_by_error_number, -error);
43
44   if (p)
45     s = format (s, "%s (%d)", p[0], error);
46   else
47     s = format (s, "%d", error);
48   return s;
49 }
50
51 static void
52   vl_api_session_enable_disable_reply_t_handler
53   (vl_api_session_enable_disable_reply_t * mp)
54 {
55   if (mp->retval)
56     {
57       clib_warning ("VCL<%d>: session_enable_disable failed: %U", getpid (),
58                     format_api_error, ntohl (mp->retval));
59     }
60   else
61     vcm->app_state = STATE_APP_ENABLED;
62 }
63
64 static void
65 vl_api_application_attach_reply_t_handler (vl_api_application_attach_reply_t *
66                                            mp)
67 {
68   static svm_fifo_segment_create_args_t _a;
69   svm_fifo_segment_create_args_t *a = &_a;
70   int rv;
71
72   memset (a, 0, sizeof (*a));
73   if (mp->retval)
74     {
75       clib_warning ("VCL<%d>: attach failed: %U", getpid (),
76                     format_api_error, ntohl (mp->retval));
77       return;
78     }
79
80   if (mp->segment_name_length == 0)
81     {
82       clib_warning ("VCL<%d>: segment_name_length zero", getpid ());
83       return;
84     }
85
86   a->segment_name = (char *) mp->segment_name;
87   a->segment_size = mp->segment_size;
88
89   ASSERT (mp->app_event_queue_address);
90
91   /* Attach to the segment vpp created */
92   rv = svm_fifo_segment_attach (a);
93   vec_reset_length (a->new_segment_indices);
94   if (PREDICT_FALSE (rv))
95     {
96       clib_warning ("VCL<%d>: svm_fifo_segment_attach ('%s') failed",
97                     getpid (), mp->segment_name);
98       return;
99     }
100
101   vcm->app_event_queue =
102     uword_to_pointer (mp->app_event_queue_address, svm_msg_q_t *);
103
104   vcm->app_state = STATE_APP_ATTACHED;
105 }
106
107 static void
108 vl_api_application_detach_reply_t_handler (vl_api_application_detach_reply_t *
109                                            mp)
110 {
111   if (mp->retval)
112     clib_warning ("VCL<%d>: detach failed: %U", getpid (), format_api_error,
113                   ntohl (mp->retval));
114
115   vcm->app_state = STATE_APP_ENABLED;
116 }
117
118 static void
119 vl_api_disconnect_session_reply_t_handler (vl_api_disconnect_session_reply_t *
120                                            mp)
121 {
122   if (mp->retval)
123     clib_warning ("VCL<%d>: vpp handle 0x%llx: disconnect session failed: %U",
124                   getpid (), mp->handle, format_api_error,
125                   ntohl (mp->retval));
126 }
127
128 static void
129 vl_api_map_another_segment_t_handler (vl_api_map_another_segment_t * mp)
130 {
131   static svm_fifo_segment_create_args_t _a;
132   svm_fifo_segment_create_args_t *a = &_a;
133   int rv;
134
135   vcm->mounting_segment = 1;
136   memset (a, 0, sizeof (*a));
137   a->segment_name = (char *) mp->segment_name;
138   a->segment_size = mp->segment_size;
139   /* Attach to the segment vpp created */
140   rv = svm_fifo_segment_attach (a);
141   vec_reset_length (a->new_segment_indices);
142   if (PREDICT_FALSE (rv))
143     {
144       clib_warning ("VCL<%d>: svm_fifo_segment_attach ('%s') failed",
145                     getpid (), mp->segment_name);
146       return;
147     }
148
149   VDBG (1, "VCL<%d>: mapped new segment '%s' size %d", getpid (),
150         mp->segment_name, mp->segment_size);
151   vcm->mounting_segment = 0;
152 }
153
154 static void
155 vl_api_unmap_segment_t_handler (vl_api_unmap_segment_t * mp)
156 {
157
158 /*
159  * XXX Need segment_name to session_id hash,
160  * XXX - have sessionID by handle hash currently
161  */
162
163   VDBG (1, "Unmapped segment '%s'", mp->segment_name);
164 }
165
166 static void
167 vl_api_disconnect_session_t_handler (vl_api_disconnect_session_t * mp)
168 {
169   uword *p;
170
171   p = hash_get (vcm->session_index_by_vpp_handles, mp->handle);
172   if (p)
173     {
174       int rv;
175       vcl_session_t *session = 0;
176       u32 session_index = p[0];
177
178       VCL_SESSION_LOCK_AND_GET (session_index, &session);
179       session->session_state = STATE_CLOSE_ON_EMPTY;
180
181       VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: setting state to 0x%x "
182             "(%s)", getpid (), mp->handle, session_index,
183             session->session_state,
184             vppcom_session_state_str (session->session_state));
185       VCL_SESSION_UNLOCK ();
186       return;
187
188     done:
189       VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: session lookup failed!",
190             getpid (), mp->handle, session_index);
191     }
192   else
193     clib_warning ("VCL<%d>: vpp handle 0x%llx: session lookup by "
194                   "handle failed!", getpid (), mp->handle);
195 }
196
197 static void
198 vl_api_reset_session_t_handler (vl_api_reset_session_t * mp)
199 {
200   vcl_session_t *session = 0;
201   vl_api_reset_session_reply_t *rmp;
202   uword *p;
203   int rv = 0;
204
205   p = hash_get (vcm->session_index_by_vpp_handles, mp->handle);
206   if (p)
207     {
208       int rval;
209       VCL_SESSION_LOCK ();
210       rval = vppcom_session_at_index (p[0], &session);
211       if (PREDICT_FALSE (rval))
212         {
213           rv = VNET_API_ERROR_INVALID_VALUE_2;
214           clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
215                         "session lookup failed! returning %d %U",
216                         getpid (), mp->handle, p[0],
217                         rv, format_api_error, rv);
218         }
219       else
220         {
221           /* TBD: should this disconnect immediately and
222            * flush the fifos?
223            */
224           session->session_state = STATE_CLOSE_ON_EMPTY;
225
226           VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: state set to %d "
227                 "(%s)!", getpid (), mp->handle, p[0], session->session_state,
228                 vppcom_session_state_str (session->session_state));
229         }
230       VCL_SESSION_UNLOCK ();
231     }
232   else
233     {
234       rv = VNET_API_ERROR_INVALID_VALUE;
235       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx: session lookup "
236                     "failed! returning %d %U",
237                     getpid (), mp->handle, rv, format_api_error, rv);
238     }
239
240   rmp = vl_msg_api_alloc (sizeof (*rmp));
241   memset (rmp, 0, sizeof (*rmp));
242   rmp->_vl_msg_id = ntohs (VL_API_RESET_SESSION_REPLY);
243   rmp->retval = htonl (rv);
244   rmp->handle = mp->handle;
245   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
246 }
247
248 static void
249 vl_api_connect_session_reply_t_handler (vl_api_connect_session_reply_t * mp)
250 {
251   vcl_session_t *session = 0;
252   u32 session_index;
253   svm_fifo_t *rx_fifo, *tx_fifo;
254   int rv = VPPCOM_OK;
255
256   session_index = mp->context;
257   VCL_SESSION_LOCK_AND_GET (session_index, &session);
258 done:
259   if (mp->retval)
260     {
261       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, sid %u: "
262                     "connect failed! %U",
263                     getpid (), mp->handle, session_index,
264                     format_api_error, ntohl (mp->retval));
265       if (session)
266         {
267           session->session_state = STATE_FAILED;
268           session->vpp_handle = mp->handle;
269         }
270       else
271         {
272           clib_warning ("[%s] ERROR: vpp handle 0x%llx, sid %u: "
273                         "Invalid session index (%u)!",
274                         getpid (), mp->handle, session_index);
275         }
276       goto done_unlock;
277     }
278
279   if (rv)
280     goto done_unlock;
281
282   /*
283    * Setup session
284    */
285   if (vcm->session_io_thread.io_sessions_lockp)
286     {
287       // Add this connection to the active io sessions list
288       VCL_IO_SESSIONS_LOCK ();
289       u32 *active_session_index;
290       pool_get (vcm->session_io_thread.active_session_indexes,
291                 active_session_index);
292       *active_session_index = session_index;
293       VCL_IO_SESSIONS_UNLOCK ();
294     }
295   session->vpp_evt_q = uword_to_pointer (mp->vpp_event_queue_address,
296                                          svm_msg_q_t *);
297
298   rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
299   rx_fifo->client_session_index = session_index;
300   tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
301   tx_fifo->client_session_index = session_index;
302
303   session->rx_fifo = rx_fifo;
304   session->tx_fifo = tx_fifo;
305   session->vpp_handle = mp->handle;
306   session->transport.is_ip4 = mp->is_ip4;
307   clib_memcpy (&session->transport.lcl_ip, mp->lcl_ip,
308                sizeof (session->transport.rmt_ip));
309   session->transport.lcl_port = mp->lcl_port;
310   session->session_state = STATE_CONNECT;
311
312   /* Add it to lookup table */
313   hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
314
315   VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: connect succeeded! "
316         "session_rx_fifo %p, refcnt %d, session_tx_fifo %p, refcnt %d",
317         getpid (), mp->handle, session_index, session->rx_fifo,
318         session->rx_fifo->refcnt, session->tx_fifo, session->tx_fifo->refcnt);
319 done_unlock:
320   VCL_SESSION_UNLOCK ();
321 }
322
323 static void
324 vl_api_bind_sock_reply_t_handler (vl_api_bind_sock_reply_t * mp)
325 {
326   vcl_session_t *session = 0;
327   u32 session_index = mp->context;
328   int rv;
329
330   VCL_SESSION_LOCK_AND_GET (session_index, &session);
331 done:
332   if (mp->retval)
333     {
334       clib_warning ("VCL<%d>: ERROR: vpp handle 0x%llx, "
335                     "sid %u: bind failed: %U",
336                     getpid (), mp->handle, session_index,
337                     format_api_error, ntohl (mp->retval));
338       rv = vppcom_session_at_index (session_index, &session);
339       if (rv == VPPCOM_OK)
340         {
341           session->session_state = STATE_FAILED;
342           session->vpp_handle = mp->handle;
343         }
344       else
345         {
346           clib_warning ("[%s] ERROR: vpp handle 0x%llx, sid %u: "
347                         "Invalid session index (%u)!",
348                         getpid (), mp->handle, session_index);
349         }
350       goto done_unlock;
351     }
352
353   session->vpp_handle = mp->handle;
354   session->transport.is_ip4 = mp->lcl_is_ip4;
355   clib_memcpy (&session->transport.lcl_ip, mp->lcl_ip,
356                sizeof (ip46_address_t));
357   session->transport.lcl_port = mp->lcl_port;
358   vppcom_session_table_add_listener (mp->handle, session_index);
359   session->session_state = STATE_LISTEN;
360
361   if (session->is_dgram)
362     {
363       svm_fifo_t *rx_fifo, *tx_fifo;
364       session->vpp_evt_q = uword_to_pointer (mp->vpp_evt_q, svm_msg_q_t *);
365       rx_fifo = uword_to_pointer (mp->rx_fifo, svm_fifo_t *);
366       rx_fifo->client_session_index = session_index;
367       tx_fifo = uword_to_pointer (mp->tx_fifo, svm_fifo_t *);
368       tx_fifo->client_session_index = session_index;
369       session->rx_fifo = rx_fifo;
370       session->tx_fifo = tx_fifo;
371     }
372
373   VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: bind succeeded!",
374         getpid (), mp->handle, mp->context);
375 done_unlock:
376   VCL_SESSION_UNLOCK ();
377 }
378
379 static void
380 vl_api_unbind_sock_reply_t_handler (vl_api_unbind_sock_reply_t * mp)
381 {
382   if (mp->retval)
383     clib_warning ("VCL<%d>: ERROR: sid %u: unbind failed: %U",
384                   getpid (), mp->context, format_api_error,
385                   ntohl (mp->retval));
386
387   else
388     VDBG (1, "VCL<%d>: sid %u: unbind succeeded!", getpid (), mp->context);
389 }
390
391 static void
392 vl_api_accept_session_t_handler (vl_api_accept_session_t * mp)
393 {
394   svm_fifo_t *rx_fifo, *tx_fifo;
395   vcl_session_t *session, *listen_session;
396   u32 session_index;
397   vce_event_connect_request_t *ecr;
398   vce_event_t *ev;
399   int rv;
400   u32 ev_idx;
401   uword elts = 0;
402
403   VCL_SESSION_LOCK ();
404
405   VCL_ACCEPT_FIFO_LOCK ();
406   elts = clib_fifo_free_elts (vcm->client_session_index_fifo);
407   VCL_ACCEPT_FIFO_UNLOCK ();
408
409   if (!elts)
410     {
411       clib_warning ("VCL<%d>: client session queue is full!", getpid ());
412       vppcom_send_accept_session_reply (mp->handle, mp->context,
413                                         VNET_API_ERROR_QUEUE_FULL);
414       VCL_SESSION_UNLOCK ();
415       return;
416     }
417
418   listen_session = vppcom_session_table_lookup_listener (mp->listener_handle);
419   if (!listen_session)
420     {
421       clib_warning ("VCL<%d>: ERROR: couldn't find listen session: "
422                     "unknown vpp listener handle %llx",
423                     getpid (), mp->listener_handle);
424       vppcom_send_accept_session_reply (mp->handle, mp->context,
425                                         VNET_API_ERROR_INVALID_ARGUMENT);
426       VCL_SESSION_UNLOCK ();
427       return;
428     }
429
430   /* TODO check listener depth and update */
431   /* TODO on "child" fd close, update listener depth */
432
433   /* Allocate local session and set it up */
434   pool_get (vcm->sessions, session);
435   memset (session, 0, sizeof (*session));
436   session_index = (u32) (session - vcm->sessions);
437
438   rx_fifo = uword_to_pointer (mp->server_rx_fifo, svm_fifo_t *);
439   rx_fifo->client_session_index = session_index;
440   tx_fifo = uword_to_pointer (mp->server_tx_fifo, svm_fifo_t *);
441   tx_fifo->client_session_index = session_index;
442
443   session->vpp_handle = mp->handle;
444   session->client_context = mp->context;
445   session->rx_fifo = rx_fifo;
446   session->tx_fifo = tx_fifo;
447   session->vpp_evt_q = uword_to_pointer (mp->vpp_event_queue_address,
448                                          svm_msg_q_t *);
449   session->session_state = STATE_ACCEPT;
450   session->transport.rmt_port = mp->port;
451   session->transport.is_ip4 = mp->is_ip4;
452   clib_memcpy (&session->transport.rmt_ip, mp->ip, sizeof (ip46_address_t));
453
454   /* Add it to lookup table */
455   hash_set (vcm->session_index_by_vpp_handles, mp->handle, session_index);
456   session->transport.lcl_port = listen_session->transport.lcl_port;
457   session->transport.lcl_ip = listen_session->transport.lcl_ip;
458
459   /* Create an event for handlers */
460
461   VCL_EVENTS_LOCK ();
462
463   pool_get (vcm->event_thread.vce_events, ev);
464   ev_idx = (u32) (ev - vcm->event_thread.vce_events);
465   ecr = vce_get_event_data (ev, sizeof (*ecr));
466   ev->evk.eid = VCL_EVENT_CONNECT_REQ_ACCEPTED;
467   listen_session = vppcom_session_table_lookup_listener (mp->listener_handle);
468   ev->evk.session_index = (u32) (listen_session - vcm->sessions);
469   ecr->accepted_session_index = session_index;
470
471   VCL_EVENTS_UNLOCK ();
472
473   rv = vce_generate_event (&vcm->event_thread, ev_idx);
474   ASSERT (rv == 0);
475
476   VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: client accept request from %s"
477         " address %U port %d queue %p!", getpid (), mp->handle, session_index,
478         mp->is_ip4 ? "IPv4" : "IPv6", format_ip46_address, &mp->ip,
479         mp->is_ip4 ? IP46_TYPE_IP4 : IP46_TYPE_IP6,
480         clib_net_to_host_u16 (mp->port), session->vpp_evt_q);
481
482   vcl_evt (VCL_EVT_ACCEPT, session, listen_session, session_index);
483   VCL_SESSION_UNLOCK ();
484 }
485
486 #define foreach_sock_msg                                        \
487 _(SESSION_ENABLE_DISABLE_REPLY, session_enable_disable_reply)   \
488 _(BIND_SOCK_REPLY, bind_sock_reply)                             \
489 _(UNBIND_SOCK_REPLY, unbind_sock_reply)                         \
490 _(ACCEPT_SESSION, accept_session)                               \
491 _(CONNECT_SESSION_REPLY, connect_session_reply)                 \
492 _(DISCONNECT_SESSION, disconnect_session)                       \
493 _(DISCONNECT_SESSION_REPLY, disconnect_session_reply)           \
494 _(RESET_SESSION, reset_session)                                 \
495 _(APPLICATION_ATTACH_REPLY, application_attach_reply)           \
496 _(APPLICATION_DETACH_REPLY, application_detach_reply)           \
497 _(MAP_ANOTHER_SEGMENT, map_another_segment)                     \
498 _(UNMAP_SEGMENT, unmap_segment)
499
500 void
501 vppcom_api_hookup (void)
502 {
503 #define _(N, n)                                                  \
504     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
505                            vl_api_##n##_t_handler,              \
506                            vl_noop_handler,                     \
507                            vl_api_##n##_t_endian,               \
508                            vl_api_##n##_t_print,                \
509                            sizeof(vl_api_##n##_t), 1);
510   foreach_sock_msg;
511 #undef _
512 }
513
514 /*
515  * VPP-API message functions
516  */
517 void
518 vppcom_send_session_enable_disable (u8 is_enable)
519 {
520   vl_api_session_enable_disable_t *bmp;
521   bmp = vl_msg_api_alloc (sizeof (*bmp));
522   memset (bmp, 0, sizeof (*bmp));
523
524   bmp->_vl_msg_id = ntohs (VL_API_SESSION_ENABLE_DISABLE);
525   bmp->client_index = vcm->my_client_index;
526   bmp->context = htonl (0xfeedface);
527   bmp->is_enable = is_enable;
528   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
529 }
530
531 void
532 vppcom_app_send_attach (void)
533 {
534   vl_api_application_attach_t *bmp;
535   u8 nsid_len = vec_len (vcm->cfg.namespace_id);
536   u8 app_is_proxy = (vcm->cfg.app_proxy_transport_tcp ||
537                      vcm->cfg.app_proxy_transport_udp);
538
539   bmp = vl_msg_api_alloc (sizeof (*bmp));
540   memset (bmp, 0, sizeof (*bmp));
541
542   bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_ATTACH);
543   bmp->client_index = vcm->my_client_index;
544   bmp->context = htonl (0xfeedface);
545   bmp->options[APP_OPTIONS_FLAGS] =
546     APP_OPTIONS_FLAGS_ACCEPT_REDIRECT | APP_OPTIONS_FLAGS_ADD_SEGMENT |
547     (vcm->cfg.app_scope_local ? APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE : 0) |
548     (vcm->cfg.app_scope_global ? APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE : 0) |
549     (app_is_proxy ? APP_OPTIONS_FLAGS_IS_PROXY : 0) |
550     APP_OPTIONS_FLAGS_USE_MQ_FOR_CTRL_MSGS;
551   bmp->options[APP_OPTIONS_PROXY_TRANSPORT] =
552     (u64) ((vcm->cfg.app_proxy_transport_tcp ? 1 << TRANSPORT_PROTO_TCP : 0) |
553            (vcm->cfg.app_proxy_transport_udp ? 1 << TRANSPORT_PROTO_UDP : 0));
554   bmp->options[APP_OPTIONS_SEGMENT_SIZE] = vcm->cfg.segment_size;
555   bmp->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = vcm->cfg.add_segment_size;
556   bmp->options[APP_OPTIONS_RX_FIFO_SIZE] = vcm->cfg.rx_fifo_size;
557   bmp->options[APP_OPTIONS_TX_FIFO_SIZE] = vcm->cfg.tx_fifo_size;
558   bmp->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
559     vcm->cfg.preallocated_fifo_pairs;
560   bmp->options[APP_OPTIONS_EVT_QUEUE_SIZE] = vcm->cfg.event_queue_size;
561   if (nsid_len)
562     {
563       bmp->namespace_id_len = nsid_len;
564       clib_memcpy (bmp->namespace_id, vcm->cfg.namespace_id, nsid_len);
565       bmp->options[APP_OPTIONS_NAMESPACE_SECRET] = vcm->cfg.namespace_secret;
566     }
567   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
568 }
569
570 void
571 vppcom_app_send_detach (void)
572 {
573   vl_api_application_detach_t *bmp;
574   bmp = vl_msg_api_alloc (sizeof (*bmp));
575   memset (bmp, 0, sizeof (*bmp));
576
577   bmp->_vl_msg_id = ntohs (VL_API_APPLICATION_DETACH);
578   bmp->client_index = vcm->my_client_index;
579   bmp->context = htonl (0xfeedface);
580   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
581 }
582
583 void
584 vppcom_send_connect_sock (vcl_session_t * session, u32 session_index)
585 {
586   vl_api_connect_sock_t *cmp;
587
588   /* Assumes caller as acquired the spinlock: vcm->sessions_lockp */
589   cmp = vl_msg_api_alloc (sizeof (*cmp));
590   memset (cmp, 0, sizeof (*cmp));
591   cmp->_vl_msg_id = ntohs (VL_API_CONNECT_SOCK);
592   cmp->client_index = vcm->my_client_index;
593   cmp->context = session_index;
594
595   cmp->is_ip4 = session->transport.is_ip4;
596   clib_memcpy (cmp->ip, &session->transport.rmt_ip, sizeof (cmp->ip));
597   cmp->port = session->transport.rmt_port;
598   cmp->proto = session->session_type;
599   clib_memcpy (cmp->options, session->options, sizeof (cmp->options));
600   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & cmp);
601 }
602
603 void
604 vppcom_send_disconnect_session_reply (u64 vpp_handle, u32 session_index,
605                                       int rv)
606 {
607   vl_api_disconnect_session_reply_t *rmp;
608
609   VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: sending disconnect msg",
610         getpid (), vpp_handle, session_index);
611
612   rmp = vl_msg_api_alloc (sizeof (*rmp));
613   memset (rmp, 0, sizeof (*rmp));
614
615   rmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION_REPLY);
616   rmp->retval = htonl (rv);
617   rmp->handle = vpp_handle;
618   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
619 }
620
621 void
622 vppcom_send_disconnect_session (u64 vpp_handle, u32 session_index)
623 {
624   vl_api_disconnect_session_t *dmp;
625
626   VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: sending disconnect msg",
627         getpid (), vpp_handle, session_index);
628
629   dmp = vl_msg_api_alloc (sizeof (*dmp));
630   memset (dmp, 0, sizeof (*dmp));
631   dmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION);
632   dmp->client_index = vcm->my_client_index;
633   dmp->handle = vpp_handle;
634   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & dmp);
635 }
636
637 /* VPP combines bind and listen as one operation. VCL manages the separation
638  * of bind and listen locally via vppcom_session_bind() and
639  * vppcom_session_listen() */
640 void
641 vppcom_send_bind_sock (vcl_session_t * session, u32 session_index)
642 {
643   vl_api_bind_sock_t *bmp;
644
645   /* Assumes caller has acquired spinlock: vcm->sessions_lockp */
646   bmp = vl_msg_api_alloc (sizeof (*bmp));
647   memset (bmp, 0, sizeof (*bmp));
648
649   bmp->_vl_msg_id = ntohs (VL_API_BIND_SOCK);
650   bmp->client_index = vcm->my_client_index;
651   bmp->context = session_index;
652   bmp->is_ip4 = session->transport.is_ip4;
653   clib_memcpy (bmp->ip, &session->transport.lcl_ip, sizeof (bmp->ip));
654   bmp->port = session->transport.lcl_port;
655   bmp->proto = session->session_type;
656   clib_memcpy (bmp->options, session->options, sizeof (bmp->options));
657   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & bmp);
658 }
659
660 void
661 vppcom_send_unbind_sock (u64 vpp_handle)
662 {
663   vl_api_unbind_sock_t *ump;
664
665   ump = vl_msg_api_alloc (sizeof (*ump));
666   memset (ump, 0, sizeof (*ump));
667
668   ump->_vl_msg_id = ntohs (VL_API_UNBIND_SOCK);
669   ump->client_index = vcm->my_client_index;
670   ump->handle = vpp_handle;
671   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & ump);
672 }
673
674 void
675 vppcom_send_accept_session_reply (u64 handle, u32 context, int retval)
676 {
677   vl_api_accept_session_reply_t *rmp;
678
679   rmp = vl_msg_api_alloc (sizeof (*rmp));
680   memset (rmp, 0, sizeof (*rmp));
681   rmp->_vl_msg_id = ntohs (VL_API_ACCEPT_SESSION_REPLY);
682   rmp->retval = htonl (retval);
683   rmp->context = context;
684   rmp->handle = handle;
685   vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
686 }
687
688 u32
689 vcl_max_nsid_len (void)
690 {
691   vl_api_application_attach_t *mp;
692   return (sizeof (mp->namespace_id) - 1);
693 }
694
695 void
696 vppcom_init_error_string_table (void)
697 {
698   vcm->error_string_by_error_number = hash_create (0, sizeof (uword));
699
700 #define _(n, v, s) hash_set (vcm->error_string_by_error_number, -v, s);
701   foreach_vnet_api_error;
702 #undef _
703
704   hash_set (vcm->error_string_by_error_number, 99, "Misc");
705 }
706
707 int
708 vppcom_connect_to_vpp (char *app_name)
709 {
710   api_main_t *am = &api_main;
711   vppcom_cfg_t *vcl_cfg = &vcm->cfg;
712   int rv = VPPCOM_OK;
713
714   if (!vcl_cfg->vpp_api_filename)
715     vcl_cfg->vpp_api_filename = format (0, "/vpe-api%c", 0);
716
717   VDBG (0, "VCL<%d>: app (%s) connecting to VPP api (%s)...",
718         getpid (), app_name, vcl_cfg->vpp_api_filename);
719
720   if (vl_client_connect_to_vlib ((char *) vcl_cfg->vpp_api_filename, app_name,
721                                  vcm->cfg.vpp_api_q_length) < 0)
722     {
723       clib_warning ("VCL<%d>: app (%s) connect failed!", getpid (), app_name);
724       rv = VPPCOM_ECONNREFUSED;
725     }
726   else
727     {
728       vcm->vl_input_queue = am->shmem_hdr->vl_input_queue;
729       vcm->my_client_index = (u32) am->my_client_index;
730       vcm->app_state = STATE_APP_CONN_VPP;
731
732       VDBG (0, "VCL<%d>: app (%s) is connected to VPP!", getpid (), app_name);
733     }
734
735   vcl_evt (VCL_EVT_INIT, vcm);
736   return rv;
737 }
738
739 /*
740  * fd.io coding-style-patch-verification: ON
741  *
742  * Local Variables:
743  * eval: (c-set-style "gnu")
744  * End:
745  */