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