api: add macro that zeros out api reply buffer
[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_ZERO(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_zero (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_MACRO_DETAILS2(t, body)                                   \
79 do {                                                                    \
80     vl_api_registration_t *rp;                                          \
81     rv = vl_msg_api_pd_handler (mp, rv);                                \
82     rp = vl_api_client_index_to_registration (mp->client_index);        \
83     if (rp == 0)                                                        \
84       return;                                                           \
85                                                                         \
86     rmp = vl_msg_api_alloc (sizeof (*rmp));                             \
87     rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE));                   \
88     rmp->context = mp->context;                                         \
89     do {body;} while (0);                                               \
90     vl_api_send_msg (rp, (u8 *)rmp);                                    \
91 } while(0);
92
93 #define REPLY_MACRO3(t, n, body)                                        \
94 do {                                                                    \
95     vl_api_registration_t *rp;                                          \
96     rv = vl_msg_api_pd_handler (mp, rv);                                \
97     rp = vl_api_client_index_to_registration (mp->client_index);        \
98     if (rp == 0)                                                        \
99       return;                                                           \
100                                                                         \
101     rmp = vl_msg_api_alloc (sizeof (*rmp) + n);                         \
102     rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE));                   \
103     rmp->context = mp->context;                                         \
104     rmp->retval = ntohl(rv);                                            \
105     do {body;} while (0);                                               \
106     vl_api_send_msg (rp, (u8 *)rmp);                                    \
107 } while(0);
108
109 #define REPLY_MACRO3_ZERO(t, n, body)                                   \
110 do {                                                                    \
111     vl_api_registration_t *rp;                                          \
112     rv = vl_msg_api_pd_handler (mp, rv);                                \
113     rp = vl_api_client_index_to_registration (mp->client_index);        \
114     if (rp == 0)                                                        \
115       return;                                                           \
116                                                                         \
117     rmp = vl_msg_api_alloc_zero (sizeof (*rmp) + n);                    \
118     rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE));                   \
119     rmp->context = mp->context;                                         \
120     rmp->retval = ntohl(rv);                                            \
121     do {body;} while (0);                                               \
122     vl_api_send_msg (rp, (u8 *)rmp);                                    \
123 } while(0);
124
125 #define REPLY_MACRO4(t, n, body)                                        \
126 do {                                                                    \
127     vl_api_registration_t *rp;                                          \
128     u8 is_error = 0;                                                    \
129     rv = vl_msg_api_pd_handler (mp, rv);                                \
130                                                                         \
131     rp = vl_api_client_index_to_registration (mp->client_index);        \
132     if (rp == 0)                                                        \
133       return;                                                           \
134                                                                         \
135     rmp = vl_msg_api_alloc_or_null (sizeof (*rmp) + n);                 \
136     if (!rmp)                                                           \
137       {                                                                 \
138         /* if there isn't enough memory, try to allocate */             \
139         /* some at least for returning an error */                      \
140         rmp = vl_msg_api_alloc (sizeof (*rmp));                         \
141         if (!rmp)                                                       \
142           return;                                                       \
143                                                                         \
144         clib_memset (rmp, 0, sizeof (*rmp));                                 \
145         rv = VNET_API_ERROR_TABLE_TOO_BIG;                              \
146         is_error = 1;                                                   \
147       }                                                                 \
148     rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE));                   \
149     rmp->context = mp->context;                                         \
150     rmp->retval = ntohl(rv);                                            \
151     if (!is_error)                                                      \
152       do {body;} while (0);                                             \
153     vl_api_send_msg (rp, (u8 *)rmp);                                    \
154 } while(0);
155
156 /* "trust, but verify" */
157
158 static inline uword
159 vnet_sw_if_index_is_api_valid (u32 sw_if_index)
160 {
161   return vnet_sw_interface_is_api_valid (vnet_get_main (), sw_if_index);
162 }
163
164 #define VALIDATE_SW_IF_INDEX(mp)                                \
165  do { u32 __sw_if_index = ntohl((mp)->sw_if_index);             \
166     if (!vnet_sw_if_index_is_api_valid(__sw_if_index)) {        \
167         rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;                \
168         goto bad_sw_if_index;                                   \
169     }                                                           \
170 } while(0);
171
172 #define BAD_SW_IF_INDEX_LABEL                   \
173 do {                                            \
174 bad_sw_if_index:                                \
175     ;                                           \
176 } while (0);
177
178 #define VALIDATE_RX_SW_IF_INDEX(mp)                             \
179  do { u32 __rx_sw_if_index = ntohl((mp)->rx_sw_if_index);       \
180     if (!vnet_sw_if_index_is_api_valid(__rx_sw_if_index)) {     \
181         rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;                \
182         goto bad_rx_sw_if_index;                                \
183     }                                                           \
184 } while(0);
185
186 #define BAD_RX_SW_IF_INDEX_LABEL                \
187 do {                                            \
188 bad_rx_sw_if_index:                             \
189     ;                                           \
190 } while (0);
191
192 #define VALIDATE_TX_SW_IF_INDEX(mp)                             \
193  do { u32 __tx_sw_if_index = ntohl(mp->tx_sw_if_index);         \
194     if (!vnet_sw_if_index_is_api_valid(__tx_sw_if_index)) {     \
195         rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;                \
196         goto bad_tx_sw_if_index;                                \
197     }                                                           \
198 } while(0);
199
200 #define BAD_TX_SW_IF_INDEX_LABEL                \
201 do {                                            \
202 bad_tx_sw_if_index:                             \
203     ;                                           \
204 } while (0);
205
206 #define VALIDATE_BD_ID(mp)                      \
207  do { u32 __rx_bd_id = ntohl(mp->bd_id);        \
208     if (__rx_bd_id > L2_BD_ID_MAX) {            \
209         rv = VNET_API_ERROR_BD_ID_EXCEED_MAX;   \
210         goto bad_bd_id;                         \
211     }                                           \
212 } while(0);
213
214 #define BAD_BD_ID_LABEL                         \
215 do {                                            \
216 bad_bd_id:                                      \
217     ;                                           \
218 } while (0);
219
220 #define pub_sub_handler(lca,UCA)                                        \
221 static void vl_api_want_##lca##_t_handler (                             \
222     vl_api_want_##lca##_t *mp)                                          \
223 {                                                                       \
224     vpe_api_main_t *vam = &vpe_api_main;                                \
225     vpe_client_registration_t *rp;                                      \
226     vl_api_want_##lca##_reply_t *rmp;                                   \
227     uword *p;                                                           \
228     i32 rv = 0;                                                         \
229                                                                         \
230     p = hash_get (vam->lca##_registration_hash, mp->client_index);      \
231     if (p) {                                                            \
232         if (mp->enable_disable) {                                       \
233             clib_warning ("pid %d: already enabled...", ntohl(mp->pid)); \
234             rv = VNET_API_ERROR_INVALID_REGISTRATION;                   \
235             goto reply;                                                 \
236         } else {                                                        \
237             rp = pool_elt_at_index (vam->lca##_registrations, p[0]);    \
238             pool_put (vam->lca##_registrations, rp);                    \
239             hash_unset (vam->lca##_registration_hash,                   \
240                 mp->client_index);                                      \
241             goto reply;                                                 \
242         }                                                               \
243     }                                                                   \
244     if (mp->enable_disable == 0) {                                      \
245         clib_warning ("pid %d: already disabled...", mp->pid);          \
246         rv = VNET_API_ERROR_INVALID_REGISTRATION;                       \
247         goto reply;                                                     \
248     }                                                                   \
249     pool_get (vam->lca##_registrations, rp);                            \
250     rp->client_index = mp->client_index;                                \
251     rp->client_pid = mp->pid;                                           \
252     hash_set (vam->lca##_registration_hash, rp->client_index,           \
253               rp - vam->lca##_registrations);                           \
254                                                                         \
255 reply:                                                                  \
256     REPLY_MACRO (VL_API_WANT_##UCA##_REPLY);                            \
257 }                                                                       \
258                                                                         \
259 static clib_error_t * vl_api_want_##lca##_t_reaper (u32 client_index)   \
260 {                                                                       \
261     vpe_api_main_t *vam = &vpe_api_main;                                \
262     vpe_client_registration_t *rp;                                      \
263     uword *p;                                                           \
264                                                                         \
265     p = hash_get (vam->lca##_registration_hash, client_index);          \
266     if (p)                                                              \
267       {                                                                 \
268         rp = pool_elt_at_index (vam->lca##_registrations, p[0]);        \
269         pool_put (vam->lca##_registrations, rp);                        \
270         hash_unset (vam->lca##_registration_hash, client_index);        \
271       }                                                                 \
272     return (NULL);                                                      \
273 }                                                                       \
274                                                                         \
275 VL_MSG_API_REAPER_FUNCTION (vl_api_want_##lca##_t_reaper);              \
276
277 #define foreach_registration_hash               \
278 _(interface_events)                             \
279 _(to_netconf_server)                            \
280 _(from_netconf_server)                          \
281 _(to_netconf_client)                            \
282 _(from_netconf_client)                          \
283 _(oam_events)                                   \
284 _(bfd_events)                                   \
285 _(l2_arp_term_events)                           \
286 _(ip6_ra_events)                                \
287 _(dhcp6_pd_reply_events)                        \
288 _(dhcp6_reply_events)
289
290 typedef struct
291 {
292   u32 client_index;             /* in memclnt registration pool */
293   u32 client_pid;
294 } vpe_client_registration_t;
295
296 typedef struct
297 {
298 #define _(a)                                            \
299   uword *a##_registration_hash;                         \
300   vpe_client_registration_t * a##_registrations;
301   foreach_registration_hash
302 #undef _
303     /* notifications happen really early in the game */
304   u8 link_state_process_up;
305
306   /* convenience */
307   vlib_main_t *vlib_main;
308   vnet_main_t *vnet_main;
309 } vpe_api_main_t;
310
311 extern vpe_api_main_t vpe_api_main;
312
313 #endif /* __api_helper_macros_h__ */
314
315 /*
316  * fd.io coding-style-patch-verification: ON
317  *
318  * Local Variables:
319  * eval: (c-set-style "gnu")
320  * End:
321  */