misc: move part of vpe apis to vlibmemory
[vpp.git] / src / vlibapi / api_helper_macros.h
1 /*
2  *------------------------------------------------------------------
3  * api_helper_macros.h - message handler helper macros
4  *
5  * Copyright (c) 2016 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 #ifndef __api_helper_macros_h__
21 #define __api_helper_macros_h__
22
23 #define f64_endian(a)
24 #define f64_print(a,b)
25
26 #ifndef REPLY_MSG_ID_BASE
27 #define REPLY_MSG_ID_BASE 0
28 #endif
29
30 #define REPLY_MACRO(t)                                                  \
31 do {                                                                    \
32     vl_api_registration_t *rp;                                          \
33     rv = vl_msg_api_pd_handler (mp, rv);                                \
34     rp = vl_api_client_index_to_registration (mp->client_index);        \
35     if (rp == 0)                                                        \
36       return;                                                           \
37                                                                         \
38     rmp = vl_msg_api_alloc (sizeof (*rmp));                             \
39     rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE));                   \
40     rmp->context = mp->context;                                         \
41     rmp->retval = ntohl(rv);                                            \
42                                                                         \
43     vl_api_send_msg (rp, (u8 *)rmp);                                    \
44 } while(0);
45
46 #define REPLY_MACRO_END(t)                                              \
47 do {                                                                    \
48     vl_api_registration_t *rp;                                          \
49     rv = vl_msg_api_pd_handler (mp, rv);                                \
50     rp = vl_api_client_index_to_registration (mp->client_index);        \
51     if (rp == 0)                                                        \
52       return;                                                           \
53                                                                         \
54     rmp = vl_msg_api_alloc (sizeof (*rmp));                             \
55     rmp->_vl_msg_id = t+(REPLY_MSG_ID_BASE);                            \
56     rmp->context = mp->context;                                         \
57     rmp->retval = rv;                                                   \
58     api_main_t *am = vlibapi_get_main ();                               \
59     void (*endian_fp) (void *);                                         \
60     endian_fp = am->msg_endian_handlers[t+(REPLY_MSG_ID_BASE)];         \
61     (*endian_fp) (rmp);                                                 \
62     vl_api_send_msg (rp, (u8 *)rmp);                                    \
63 } while(0);
64
65 #define REPLY_MACRO2(t, body)                                           \
66 do {                                                                    \
67     vl_api_registration_t *rp;                                          \
68     rv = vl_msg_api_pd_handler (mp, rv);                                \
69     rp = vl_api_client_index_to_registration (mp->client_index);        \
70     if (rp == 0)                                                        \
71       return;                                                           \
72                                                                         \
73     rmp = vl_msg_api_alloc (sizeof (*rmp));                             \
74     rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE));                   \
75     rmp->context = mp->context;                                         \
76     rmp->retval = ntohl(rv);                                            \
77     do {body;} while (0);                                               \
78     vl_api_send_msg (rp, (u8 *)rmp);                                    \
79 } while(0);
80
81 #define REPLY_MACRO2_END(t, body)                                       \
82 do {                                                                    \
83     vl_api_registration_t *rp;                                          \
84     rv = vl_msg_api_pd_handler (mp, rv);                                \
85     rp = vl_api_client_index_to_registration (mp->client_index);        \
86     if (rp == 0)                                                        \
87       return;                                                           \
88                                                                         \
89     rmp = vl_msg_api_alloc (sizeof (*rmp));                             \
90     rmp->_vl_msg_id = t+(REPLY_MSG_ID_BASE);                            \
91     rmp->context = mp->context;                                         \
92     rmp->retval = rv;                                                   \
93     do {body;} while (0);                                               \
94     api_main_t *am = vlibapi_get_main ();                               \
95     void (*endian_fp) (void *);                                         \
96     endian_fp = am->msg_endian_handlers[t+(REPLY_MSG_ID_BASE)];         \
97     (*endian_fp) (rmp);                                                 \
98     vl_api_send_msg (rp, (u8 *)rmp);                                    \
99 } while(0);
100
101 #define REPLY_MACRO2_ZERO(t, body)                                      \
102 do {                                                                    \
103     vl_api_registration_t *rp;                                          \
104     rv = vl_msg_api_pd_handler (mp, rv);                                \
105     rp = vl_api_client_index_to_registration (mp->client_index);        \
106     if (rp == 0)                                                        \
107       return;                                                           \
108                                                                         \
109     rmp = vl_msg_api_alloc_zero (sizeof (*rmp));                        \
110     rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE));                   \
111     rmp->context = mp->context;                                         \
112     rmp->retval = ntohl(rv);                                            \
113     do {body;} while (0);                                               \
114     vl_api_send_msg (rp, (u8 *)rmp);                                    \
115 } while(0);
116
117 #define REPLY_MACRO_DETAILS2(t, body)                                   \
118 do {                                                                    \
119     vl_api_registration_t *rp;                                          \
120     rv = vl_msg_api_pd_handler (mp, rv);                                \
121     rp = vl_api_client_index_to_registration (mp->client_index);        \
122     if (rp == 0)                                                        \
123       return;                                                           \
124                                                                         \
125     rmp = vl_msg_api_alloc (sizeof (*rmp));                             \
126     rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE));                   \
127     rmp->context = mp->context;                                         \
128     do {body;} while (0);                                               \
129     vl_api_send_msg (rp, (u8 *)rmp);                                    \
130 } while(0);
131
132 #define REPLY_MACRO_DETAILS4(t, rp, context, body)                      \
133 do {                                                                    \
134     rmp = vl_msg_api_alloc (sizeof (*rmp));                             \
135     rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE));                   \
136     rmp->context = context;                                             \
137     do {body;} while (0);                                               \
138     vl_api_send_msg (rp, (u8 *)rmp);                                    \
139 } while(0);
140
141 #define REPLY_MACRO3(t, n, body)                                        \
142 do {                                                                    \
143     vl_api_registration_t *rp;                                          \
144     rv = vl_msg_api_pd_handler (mp, rv);                                \
145     rp = vl_api_client_index_to_registration (mp->client_index);        \
146     if (rp == 0)                                                        \
147       return;                                                           \
148                                                                         \
149     rmp = vl_msg_api_alloc (sizeof (*rmp) + n);                         \
150     rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE));                   \
151     rmp->context = mp->context;                                         \
152     rmp->retval = ntohl(rv);                                            \
153     do {body;} while (0);                                               \
154     vl_api_send_msg (rp, (u8 *)rmp);                                    \
155 } while(0);
156
157 #define REPLY_MACRO3_ZERO(t, n, body)                                   \
158 do {                                                                    \
159     vl_api_registration_t *rp;                                          \
160     rv = vl_msg_api_pd_handler (mp, rv);                                \
161     rp = vl_api_client_index_to_registration (mp->client_index);        \
162     if (rp == 0)                                                        \
163       return;                                                           \
164                                                                         \
165     rmp = vl_msg_api_alloc_zero (sizeof (*rmp) + n);                    \
166     rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE));                   \
167     rmp->context = mp->context;                                         \
168     rmp->retval = ntohl(rv);                                            \
169     do {body;} while (0);                                               \
170     vl_api_send_msg (rp, (u8 *)rmp);                                    \
171 } while(0);
172
173 #define REPLY_MACRO4(t, n, body)                                        \
174 do {                                                                    \
175     vl_api_registration_t *rp;                                          \
176     u8 is_error = 0;                                                    \
177     rv = vl_msg_api_pd_handler (mp, rv);                                \
178                                                                         \
179     rp = vl_api_client_index_to_registration (mp->client_index);        \
180     if (rp == 0)                                                        \
181       return;                                                           \
182                                                                         \
183     rmp = vl_msg_api_alloc_or_null (sizeof (*rmp) + n);                 \
184     if (!rmp)                                                           \
185       {                                                                 \
186         /* if there isn't enough memory, try to allocate */             \
187         /* some at least for returning an error */                      \
188         rmp = vl_msg_api_alloc (sizeof (*rmp));                         \
189         if (!rmp)                                                       \
190           return;                                                       \
191                                                                         \
192         clib_memset (rmp, 0, sizeof (*rmp));                                 \
193         rv = VNET_API_ERROR_TABLE_TOO_BIG;                              \
194         is_error = 1;                                                   \
195       }                                                                 \
196     rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE));                   \
197     rmp->context = mp->context;                                         \
198     rmp->retval = ntohl(rv);                                            \
199     if (!is_error)                                                      \
200       do {body;} while (0);                                             \
201     vl_api_send_msg (rp, (u8 *)rmp);                                    \
202 } while(0);
203
204 #define REPLY_AND_DETAILS_MACRO(t, p, body)                                   \
205   do                                                                          \
206     {                                                                         \
207       if (pool_elts (p) == 0)                                                 \
208         {                                                                     \
209           REPLY_MACRO (t);                                                    \
210           break;                                                              \
211         }                                                                     \
212       vl_api_registration_t *rp;                                              \
213       rp = vl_api_client_index_to_registration (mp->client_index);            \
214       if (rp == 0)                                                            \
215         return;                                                               \
216       u32 cursor = clib_net_to_host_u32 (mp->cursor);                         \
217       vlib_main_t *vm = vlib_get_main ();                                     \
218       f64 start = vlib_time_now (vm);                                         \
219       if (pool_is_free_index (p, cursor))                                     \
220         {                                                                     \
221           cursor = pool_next_index (p, cursor);                               \
222           if (cursor == ~0)                                                   \
223             rv = VNET_API_ERROR_INVALID_VALUE;                                \
224         }                                                                     \
225       while (cursor != ~0)                                                    \
226         {                                                                     \
227           do                                                                  \
228             {                                                                 \
229               body;                                                           \
230             }                                                                 \
231           while (0);                                                          \
232           cursor = pool_next_index (p, cursor);                               \
233           if (vl_api_process_may_suspend (vm, rp, start))                     \
234             {                                                                 \
235               if (cursor != ~0)                                               \
236                 rv = VNET_API_ERROR_EAGAIN;                                   \
237               break;                                                          \
238             }                                                                 \
239         }                                                                     \
240       REPLY_MACRO2 (t, ({ rmp->cursor = clib_host_to_net_u32 (cursor); }));   \
241     }                                                                         \
242   while (0);
243
244 #define REPLY_AND_DETAILS_VEC_MACRO(t, v, mp, rmp, rv, body)    \
245 do {                                                            \
246   vl_api_registration_t *rp;                                    \
247   rp = vl_api_client_index_to_registration (mp->client_index);  \
248   if (rp == 0)                                                  \
249     return;                                                     \
250   u32 cursor = clib_net_to_host_u32 (mp->cursor);               \
251   vlib_main_t *vm = vlib_get_main ();                           \
252   f64 start = vlib_time_now (vm);                               \
253   if (!v || vec_len (v) == 0) {                                 \
254     cursor = ~0;                                                \
255     rv = VNET_API_ERROR_INVALID_VALUE;                          \
256   } else if (cursor == ~0)                                      \
257       cursor = 0;                                               \
258   while (cursor != ~0 && cursor < vec_len (v)) {                \
259     do {body;} while (0);                                       \
260     ++cursor;                                                   \
261     if (vl_api_process_may_suspend (vm, rp, start)) {           \
262       if (cursor < vec_len (v))                                 \
263         rv = VNET_API_ERROR_EAGAIN;                             \
264       break;                                                    \
265     }                                                           \
266   }                                                             \
267   REPLY_MACRO2 (t, ({                                           \
268     rmp->cursor = clib_host_to_net_u32 (cursor);                \
269   }));                                                          \
270 } while(0);
271
272
273 /* "trust, but verify" */
274 #define vnet_sw_if_index_is_api_valid(sw_if_index)                            \
275   vnet_sw_interface_is_api_valid (vnet_get_main (), sw_if_index)
276
277 #define VALIDATE_SW_IF_INDEX(mp)                                \
278  do { u32 __sw_if_index = ntohl((mp)->sw_if_index);             \
279     if (!vnet_sw_if_index_is_api_valid(__sw_if_index)) {        \
280         rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;                \
281         goto bad_sw_if_index;                                   \
282     }                                                           \
283 } while(0);
284
285 #define BAD_SW_IF_INDEX_LABEL                   \
286 do {                                            \
287 bad_sw_if_index:                                \
288     ;                                           \
289 } while (0);
290
291 #define VALIDATE_RX_SW_IF_INDEX(mp)                             \
292  do { u32 __rx_sw_if_index = ntohl((mp)->rx_sw_if_index);       \
293     if (!vnet_sw_if_index_is_api_valid(__rx_sw_if_index)) {     \
294         rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;                \
295         goto bad_rx_sw_if_index;                                \
296     }                                                           \
297 } while(0);
298
299 #define BAD_RX_SW_IF_INDEX_LABEL                \
300 do {                                            \
301 bad_rx_sw_if_index:                             \
302     ;                                           \
303 } while (0);
304
305 #define VALIDATE_TX_SW_IF_INDEX(mp)                             \
306  do { u32 __tx_sw_if_index = ntohl(mp->tx_sw_if_index);         \
307     if (!vnet_sw_if_index_is_api_valid(__tx_sw_if_index)) {     \
308         rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;                \
309         goto bad_tx_sw_if_index;                                \
310     }                                                           \
311 } while(0);
312
313 #define BAD_TX_SW_IF_INDEX_LABEL                \
314 do {                                            \
315 bad_tx_sw_if_index:                             \
316     ;                                           \
317 } while (0);
318
319 #define VALIDATE_BD_ID(mp)                      \
320  do { u32 __rx_bd_id = ntohl(mp->bd_id);        \
321     if (__rx_bd_id > L2_BD_ID_MAX) {            \
322         rv = VNET_API_ERROR_BD_ID_EXCEED_MAX;   \
323         goto bad_bd_id;                         \
324     }                                           \
325 } while(0);
326
327 #define BAD_BD_ID_LABEL                         \
328 do {                                            \
329 bad_bd_id:                                      \
330     ;                                           \
331 } while (0);
332
333 #define pub_sub_handler(lca,UCA)                                        \
334 static void vl_api_want_##lca##_t_handler (                             \
335     vl_api_want_##lca##_t *mp)                                          \
336 {                                                                       \
337     vpe_api_main_t *vam = &vpe_api_main;                                \
338     vpe_client_registration_t *rp;                                      \
339     vl_api_want_##lca##_reply_t *rmp;                                   \
340     uword *p;                                                           \
341     i32 rv = 0;                                                         \
342                                                                         \
343     p = hash_get (vam->lca##_registration_hash, mp->client_index);      \
344     if (p) {                                                            \
345         if (mp->enable_disable) {                                       \
346             clib_warning ("pid %d: already enabled...", ntohl(mp->pid)); \
347             rv = VNET_API_ERROR_INVALID_REGISTRATION;                   \
348             goto reply;                                                 \
349         } else {                                                        \
350             rp = pool_elt_at_index (vam->lca##_registrations, p[0]);    \
351             pool_put (vam->lca##_registrations, rp);                    \
352             hash_unset (vam->lca##_registration_hash,                   \
353                 mp->client_index);                                      \
354             goto reply;                                                 \
355         }                                                               \
356     }                                                                   \
357     if (mp->enable_disable == 0) {                                      \
358         clib_warning ("pid %d: already disabled...", mp->pid);          \
359         rv = VNET_API_ERROR_INVALID_REGISTRATION;                       \
360         goto reply;                                                     \
361     }                                                                   \
362     pool_get (vam->lca##_registrations, rp);                            \
363     rp->client_index = mp->client_index;                                \
364     rp->client_pid = mp->pid;                                           \
365     hash_set (vam->lca##_registration_hash, rp->client_index,           \
366               rp - vam->lca##_registrations);                           \
367                                                                         \
368 reply:                                                                  \
369     REPLY_MACRO (VL_API_WANT_##UCA##_REPLY);                            \
370 }                                                                       \
371                                                                         \
372 static clib_error_t * vl_api_want_##lca##_t_reaper (u32 client_index)   \
373 {                                                                       \
374     vpe_api_main_t *vam = &vpe_api_main;                                \
375     vpe_client_registration_t *rp;                                      \
376     uword *p;                                                           \
377                                                                         \
378     p = hash_get (vam->lca##_registration_hash, client_index);          \
379     if (p)                                                              \
380       {                                                                 \
381         rp = pool_elt_at_index (vam->lca##_registrations, p[0]);        \
382         pool_put (vam->lca##_registrations, rp);                        \
383         hash_unset (vam->lca##_registration_hash, client_index);        \
384       }                                                                 \
385     return (NULL);                                                      \
386 }                                                                       \
387                                                                         \
388 VL_MSG_API_REAPER_FUNCTION (vl_api_want_##lca##_t_reaper);              \
389
390 #define foreach_registration_hash               \
391 _(interface_events)                             \
392 _(to_netconf_server)                            \
393 _(from_netconf_server)                          \
394 _(to_netconf_client)                            \
395 _(from_netconf_client)                          \
396 _(oam_events)                                   \
397 _(bfd_events)                                   \
398 _(l2_arp_term_events)                           \
399 _(ip6_ra_events)                                \
400 _(dhcp6_pd_reply_events)                        \
401 _(dhcp6_reply_events)                           \
402 _(vrrp_vr_events)
403
404 typedef struct
405 {
406   u32 client_index;             /* in memclnt registration pool */
407   u32 client_pid;
408 } vpe_client_registration_t;
409
410 typedef struct
411 {
412 #define _(a)                                            \
413   uword *a##_registration_hash;                         \
414   vpe_client_registration_t * a##_registrations;
415   foreach_registration_hash
416 #undef _
417     /* notifications happen really early in the game */
418   u8 link_state_process_up;
419
420   /* convenience */
421   vlib_main_t *vlib_main;
422   struct vnet_main_t *vnet_main;
423 } vpe_api_main_t;
424
425 extern vpe_api_main_t vpe_api_main;
426
427 #endif /* __api_helper_macros_h__ */
428
429 /*
430  * fd.io coding-style-patch-verification: ON
431  *
432  * Local Variables:
433  * eval: (c-set-style "gnu")
434  * End:
435  */