blob: 126c74a129065cdbd8473a5668bef9e8309a6cc5 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 *------------------------------------------------------------------
3 * memory_client.c - API message handling, client code.
4 *
5 * Copyright (c) 2010 Cisco and/or its affiliates.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *------------------------------------------------------------------
18 */
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <setjmp.h>
23#include <sys/types.h>
24#include <sys/mman.h>
25#include <sys/stat.h>
26#include <netinet/in.h>
27#include <signal.h>
28#include <pthread.h>
29#include <unistd.h>
30#include <time.h>
31#include <fcntl.h>
32#include <string.h>
33#include <vppinfra/clib.h>
34#include <vppinfra/vec.h>
35#include <vppinfra/hash.h>
36#include <vppinfra/bitmap.h>
37#include <vppinfra/fifo.h>
38#include <vppinfra/time.h>
39#include <vppinfra/mheap.h>
40#include <vppinfra/heap.h>
41#include <vppinfra/pool.h>
42#include <vppinfra/format.h>
43
44#include <vlib/vlib.h>
45#include <vlib/unix/unix.h>
46#include <vlibmemory/api.h>
47
48#include <vlibmemory/vl_memory_msg_enum.h>
49
50#define vl_typedefs /* define message structures */
51#include <vlibmemory/vl_memory_api_h.h>
52#undef vl_typedefs
53
54#define vl_endianfun /* define message structures */
55#include <vlibmemory/vl_memory_api_h.h>
56#undef vl_endianfun
57
58/* instantiate all the print functions we know about */
59#define vl_print(handle, ...) clib_warning (__VA_ARGS__)
60#define vl_printfun
61#include <vlibmemory/vl_memory_api_h.h>
62#undef vl_printfun
63
64typedef struct {
65 u8 rx_thread_jmpbuf_valid;
66 u8 connected_to_vlib;
67 jmp_buf rx_thread_jmpbuf;
68 pthread_t rx_thread_handle;
69 /* Plugin message base lookup scheme */
70 volatile u8 first_msg_id_reply_ready;
71 u16 first_msg_id_reply;
72} memory_client_main_t;
73
74memory_client_main_t memory_client_main;
75
76static void *rx_thread_fn(void *arg)
77{
78 unix_shared_memory_queue_t *q;
79 memory_client_main_t *mm = &memory_client_main;
80 api_main_t *am = &api_main;
81
82 q = am->vl_input_queue;
83
84 /* So we can make the rx thread terminate cleanly */
85 if (setjmp(mm->rx_thread_jmpbuf) == 0) {
86 mm->rx_thread_jmpbuf_valid = 1;
87 while (1) {
88 vl_msg_api_queue_handler (q);
89 }
90 }
91 pthread_exit(0);
92}
93
94static void vl_api_rx_thread_exit_t_handler (
95 vl_api_rx_thread_exit_t *mp)
96{
97 memory_client_main_t *mm = &memory_client_main;
98 vl_msg_api_free (mp);
99 longjmp (mm->rx_thread_jmpbuf, 1);
100}
101
102static void noop_handler (void *notused)
103{
104}
105
106#define foreach_api_msg \
107_(RX_THREAD_EXIT, rx_thread_exit)
108
109static int connect_to_vlib_internal (char *svm_name, char *client_name,
110 int rx_queue_size, int want_pthread)
111{
112 int rv=0;
113 memory_client_main_t *mm = &memory_client_main;
114
115 if ((rv = vl_client_api_map(svm_name))) {
116 clib_warning ("vl_client_api map rv %d", rv);
117 return rv;
118 }
119
120#define _(N,n) \
121 vl_msg_api_set_handlers(VL_API_##N, #n, \
122 vl_api_##n##_t_handler, \
123 noop_handler, \
124 vl_api_##n##_t_endian, \
125 vl_api_##n##_t_print, \
126 sizeof(vl_api_##n##_t), 1);
127 foreach_api_msg;
128#undef _
129
130 if (vl_client_connect(client_name, 0 /* punt quota */,
131 rx_queue_size /* input queue */) < 0) {
132 vl_client_api_unmap();
133 return -1;
134 }
135
136 /* Start the rx queue thread */
137
138 if (want_pthread) {
139 rv = pthread_create(&mm->rx_thread_handle,
140 NULL /*attr*/, rx_thread_fn, 0);
141 if (rv)
142 clib_warning("pthread_create returned %d", rv);
143 }
144
145 mm->connected_to_vlib = 1;
146 return 0;
147}
148
149int vl_client_connect_to_vlib(char *svm_name, char *client_name,
150 int rx_queue_size)
151{
152 return connect_to_vlib_internal (svm_name, client_name, rx_queue_size,
153 1 /* want pthread */);
154}
155
156int vl_client_connect_to_vlib_no_rx_pthread (char *svm_name, char *client_name,
157 int rx_queue_size)
158{
159 return connect_to_vlib_internal (svm_name, client_name, rx_queue_size,
160 0 /* want pthread */);
161}
162
163void vl_client_disconnect_from_vlib (void)
164{
165 memory_client_main_t *mm = &memory_client_main;
166 api_main_t *am = &api_main;
167 uword junk;
168
169 if (mm->rx_thread_jmpbuf_valid) {
170 vl_api_rx_thread_exit_t *ep;
171 ep = vl_msg_api_alloc (sizeof (*ep));
172 ep->_vl_msg_id = ntohs(VL_API_RX_THREAD_EXIT);
173 vl_msg_api_send_shmem (am->vl_input_queue, (u8 *)&ep);
174 pthread_join (mm->rx_thread_handle, (void **) &junk);
175 }
176 if (mm->connected_to_vlib) {
177 vl_client_disconnect();
178 vl_client_api_unmap();
179 }
180 memset (mm, 0, sizeof (*mm));
181}
182
183static void vl_api_get_first_msg_id_reply_t_handler
184(vl_api_get_first_msg_id_reply_t * mp)
185{
186 memory_client_main_t *mm = &memory_client_main;
187 i32 retval = ntohl(mp->retval);
188
189 mm->first_msg_id_reply = (retval >= 0) ? ntohs(mp->first_msg_id) : ~0;
190 mm->first_msg_id_reply_ready = 1;
191}
192
193u16 vl_client_get_first_plugin_msg_id (char * plugin_name)
194{
195 vl_api_get_first_msg_id_t * mp;
196 api_main_t * am = &api_main;
197 memory_client_main_t * mm = &memory_client_main;
198 f64 timeout;
199 void * old_handler;
200 clib_time_t clib_time;
201 u16 rv = ~0;
202
203 if (strlen(plugin_name) + 1 > sizeof (mp->name))
204 return (rv);
205
206 memset (&clib_time, 0, sizeof (clib_time));
207 clib_time_init (&clib_time);
208
209 /* Push this plugin's first_msg_id_reply handler */
210 old_handler = am->msg_handlers[VL_API_GET_FIRST_MSG_ID_REPLY];
211 am->msg_handlers[VL_API_GET_FIRST_MSG_ID_REPLY] = (void *)
212 vl_api_get_first_msg_id_reply_t_handler;
213
214 /* Ask the data-plane for the message-ID base of the indicated plugin */
215 mm->first_msg_id_reply_ready = 0;
216
217 mp = vl_msg_api_alloc (sizeof(*mp));
218 memset (mp, 0, sizeof (*mp));
219 mp->_vl_msg_id = ntohs(VL_API_GET_FIRST_MSG_ID);
220 mp->client_index = am->my_client_index;
221 strncpy ((char *) mp->name, plugin_name, sizeof (mp->name) - 1);
222
223 vl_msg_api_send_shmem (am->shmem_hdr->vl_input_queue, (u8 *)&mp);
224
225 /* Synchronously wait for the answer */
226 do {
227 timeout = clib_time_now (&clib_time) + 1.0;
228
229 while (clib_time_now (&clib_time) < timeout) {
230 if (mm->first_msg_id_reply_ready == 1) {
231 rv = mm->first_msg_id_reply;
232 goto result;
233 }
234 }
235 /* Restore old handler */
236 am->msg_handlers[VL_API_GET_FIRST_MSG_ID_REPLY] = old_handler;
237
238 return rv;
239 } while(0);
240
241result:
242
243 /* Restore the old handler */
244 am->msg_handlers[VL_API_GET_FIRST_MSG_ID_REPLY] = old_handler;
245
246 if (rv == (u16) ~0)
247 clib_warning ("plugin '%s' not registered", plugin_name);
248
249 return rv;
250}