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