GBP V2
[vpp.git] / src / plugins / gbp / gbp_api.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2018 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <vnet/vnet.h>
19 #include <vnet/plugin/plugin.h>
20
21 #include <vnet/interface.h>
22 #include <vnet/api_errno.h>
23 #include <vpp/app/version.h>
24
25 #include <gbp/gbp.h>
26
27 #include <vlibapi/api.h>
28 #include <vlibmemory/api.h>
29
30 /* define message IDs */
31 #include <gbp/gbp_msg_enum.h>
32
33 #define vl_typedefs             /* define message structures */
34 #include <gbp/gbp_all_api_h.h>
35 #undef vl_typedefs
36
37 #define vl_endianfun            /* define message structures */
38 #include <gbp/gbp_all_api_h.h>
39 #undef vl_endianfun
40
41 /* instantiate all the print functions we know about */
42 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
43 #define vl_printfun
44 #include <gbp/gbp_all_api_h.h>
45 #undef vl_printfun
46
47 /* Get the API version number */
48 #define vl_api_version(n,v) static u32 api_version=(v);
49 #include <acl/acl_all_api_h.h>
50 #undef vl_api_version
51
52 #include <vlibapi/api_helper_macros.h>
53
54 #define foreach_gbp_api_msg                                 \
55   _(GBP_ENDPOINT_ADD_DEL, gbp_endpoint_add_del)             \
56   _(GBP_ENDPOINT_DUMP, gbp_endpoint_dump)                   \
57   _(GBP_SUBNET_ADD_DEL, gbp_subnet_add_del)                 \
58   _(GBP_SUBNET_DUMP, gbp_subnet_dump)                       \
59   _(GBP_ENDPOINT_GROUP_ADD_DEL, gbp_endpoint_group_add_del) \
60   _(GBP_ENDPOINT_GROUP_DUMP, gbp_endpoint_group_dump)       \
61   _(GBP_RECIRC_ADD_DEL, gbp_recirc_add_del)                 \
62   _(GBP_RECIRC_DUMP, gbp_recirc_dump)                       \
63   _(GBP_CONTRACT_ADD_DEL, gbp_contract_add_del)             \
64   _(GBP_CONTRACT_DUMP, gbp_contract_dump)
65
66 /**
67  * L2 Emulation Main
68  */
69 typedef struct gbp_main_t_
70 {
71   u16 msg_id_base;
72 } gbp_main_t;
73
74 static gbp_main_t gbp_main;
75
76 #define GBP_MSG_BASE gbp_main.msg_id_base
77
78 static void
79 vl_api_gbp_endpoint_add_del_t_handler (vl_api_gbp_endpoint_add_del_t * mp)
80 {
81   vl_api_gbp_endpoint_add_del_reply_t *rmp;
82   ip46_address_t ip = { };
83   u32 sw_if_index;
84   int rv = 0;
85
86   sw_if_index = ntohl (mp->endpoint.sw_if_index);
87   if (!vnet_sw_if_index_is_api_valid (sw_if_index))
88     goto bad_sw_if_index;
89
90   if (mp->endpoint.is_ip6)
91     {
92       clib_memcpy (&ip.ip6, mp->endpoint.address, sizeof (ip.ip6));
93     }
94   else
95     {
96       clib_memcpy (&ip.ip4, mp->endpoint.address, sizeof (ip.ip4));
97     }
98
99   if (mp->is_add)
100     {
101       rv =
102         gbp_endpoint_update (sw_if_index, &ip, ntohl (mp->endpoint.epg_id));
103     }
104   else
105     {
106       gbp_endpoint_delete (sw_if_index, &ip);
107     }
108
109   BAD_SW_IF_INDEX_LABEL;
110
111   REPLY_MACRO (VL_API_GBP_ENDPOINT_ADD_DEL_REPLY + GBP_MSG_BASE);
112 }
113
114 typedef struct gbp_walk_ctx_t_
115 {
116   vl_api_registration_t *reg;
117   u32 context;
118 } gbp_walk_ctx_t;
119
120 static int
121 gbp_endpoint_send_details (gbp_endpoint_t * gbpe, void *args)
122 {
123   vl_api_gbp_endpoint_details_t *mp;
124   gbp_walk_ctx_t *ctx;
125
126   ctx = args;
127   mp = vl_msg_api_alloc (sizeof (*mp));
128   if (!mp)
129     return 1;
130
131   memset (mp, 0, sizeof (*mp));
132   mp->_vl_msg_id = ntohs (VL_API_GBP_ENDPOINT_DETAILS + GBP_MSG_BASE);
133   mp->context = ctx->context;
134
135   mp->endpoint.sw_if_index = ntohl (gbpe->ge_key->gek_sw_if_index);
136   mp->endpoint.is_ip6 = !ip46_address_is_ip4 (&gbpe->ge_key->gek_ip);
137   if (mp->endpoint.is_ip6)
138     clib_memcpy (&mp->endpoint.address,
139                  &gbpe->ge_key->gek_ip.ip6,
140                  sizeof (gbpe->ge_key->gek_ip.ip6));
141   else
142     clib_memcpy (&mp->endpoint.address,
143                  &gbpe->ge_key->gek_ip.ip4,
144                  sizeof (gbpe->ge_key->gek_ip.ip4));
145
146   mp->endpoint.epg_id = ntohl (gbpe->ge_epg_id);
147
148   vl_api_send_msg (ctx->reg, (u8 *) mp);
149
150   return (1);
151 }
152
153 static void
154 vl_api_gbp_endpoint_dump_t_handler (vl_api_gbp_endpoint_dump_t * mp)
155 {
156   vl_api_registration_t *reg;
157
158   reg = vl_api_client_index_to_registration (mp->client_index);
159   if (!reg)
160     return;
161
162   gbp_walk_ctx_t ctx = {
163     .reg = reg,
164     .context = mp->context,
165   };
166
167   gbp_endpoint_walk (gbp_endpoint_send_details, &ctx);
168 }
169
170 static void
171   vl_api_gbp_endpoint_group_add_del_t_handler
172   (vl_api_gbp_endpoint_group_add_del_t * mp)
173 {
174   vl_api_gbp_endpoint_group_add_del_reply_t *rmp;
175   u32 uplink_sw_if_index;
176   int rv = 0;
177
178   uplink_sw_if_index = ntohl (mp->epg.uplink_sw_if_index);
179   if (!vnet_sw_if_index_is_api_valid (uplink_sw_if_index))
180     goto bad_sw_if_index;
181
182   if (mp->is_add)
183     {
184       rv = gbp_endpoint_group_add (ntohl (mp->epg.epg_id),
185                                    ntohl (mp->epg.bd_id),
186                                    ntohl (mp->epg.ip4_table_id),
187                                    ntohl (mp->epg.ip6_table_id),
188                                    uplink_sw_if_index);
189     }
190   else
191     {
192       gbp_endpoint_group_delete (ntohl (mp->epg.epg_id));
193     }
194
195   BAD_SW_IF_INDEX_LABEL;
196
197   REPLY_MACRO (VL_API_GBP_ENDPOINT_GROUP_ADD_DEL_REPLY + GBP_MSG_BASE);
198 }
199
200 static void
201 vl_api_gbp_subnet_add_del_t_handler (vl_api_gbp_subnet_add_del_t * mp)
202 {
203   vl_api_gbp_subnet_add_del_reply_t *rmp;
204   int rv = 0;
205   fib_prefix_t pfx = {
206     .fp_len = mp->subnet.address_length,
207     .fp_proto = (mp->subnet.is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4),
208   };
209
210   if (mp->subnet.is_ip6)
211     clib_memcpy (&pfx.fp_addr.ip6, mp->subnet.address,
212                  sizeof (pfx.fp_addr.ip6));
213   else
214     clib_memcpy (&pfx.fp_addr.ip4, mp->subnet.address,
215                  sizeof (pfx.fp_addr.ip4));
216
217   rv = gbp_subnet_add_del (ntohl (mp->subnet.table_id),
218                            &pfx,
219                            ntohl (mp->subnet.sw_if_index),
220                            ntohl (mp->subnet.epg_id),
221                            mp->is_add, mp->subnet.is_internal);
222
223   REPLY_MACRO (VL_API_GBP_SUBNET_ADD_DEL_REPLY + GBP_MSG_BASE);
224 }
225
226 static int
227 gbp_subnet_send_details (u32 table_id,
228                          const fib_prefix_t * pfx,
229                          u32 sw_if_index,
230                          epg_id_t epg, u8 is_internal, void *args)
231 {
232   vl_api_gbp_subnet_details_t *mp;
233   gbp_walk_ctx_t *ctx;
234
235   ctx = args;
236   mp = vl_msg_api_alloc (sizeof (*mp));
237   if (!mp)
238     return 1;
239
240   memset (mp, 0, sizeof (*mp));
241   mp->_vl_msg_id = ntohs (VL_API_GBP_SUBNET_DETAILS + GBP_MSG_BASE);
242   mp->context = ctx->context;
243
244   mp->subnet.is_internal = is_internal;
245   mp->subnet.sw_if_index = ntohl (sw_if_index);
246   mp->subnet.epg_id = ntohl (epg);
247   mp->subnet.is_ip6 = (pfx->fp_proto == FIB_PROTOCOL_IP6);
248   mp->subnet.address_length = pfx->fp_len;
249   mp->subnet.table_id = ntohl (table_id);
250   if (mp->subnet.is_ip6)
251     clib_memcpy (&mp->subnet.address,
252                  &pfx->fp_addr.ip6, sizeof (pfx->fp_addr.ip6));
253   else
254     clib_memcpy (&mp->subnet.address,
255                  &pfx->fp_addr.ip4, sizeof (pfx->fp_addr.ip4));
256
257
258   vl_api_send_msg (ctx->reg, (u8 *) mp);
259
260   return (1);
261 }
262
263 static void
264 vl_api_gbp_subnet_dump_t_handler (vl_api_gbp_subnet_dump_t * mp)
265 {
266   vl_api_registration_t *reg;
267
268   reg = vl_api_client_index_to_registration (mp->client_index);
269   if (!reg)
270     return;
271
272   gbp_walk_ctx_t ctx = {
273     .reg = reg,
274     .context = mp->context,
275   };
276
277   gbp_subnet_walk (gbp_subnet_send_details, &ctx);
278 }
279
280 static int
281 gbp_endpoint_group_send_details (gbp_endpoint_group_t * gepg, void *args)
282 {
283   vl_api_gbp_endpoint_group_details_t *mp;
284   gbp_walk_ctx_t *ctx;
285
286   ctx = args;
287   mp = vl_msg_api_alloc (sizeof (*mp));
288   if (!mp)
289     return 1;
290
291   memset (mp, 0, sizeof (*mp));
292   mp->_vl_msg_id = ntohs (VL_API_GBP_ENDPOINT_GROUP_DETAILS + GBP_MSG_BASE);
293   mp->context = ctx->context;
294
295   mp->epg.uplink_sw_if_index = ntohl (gepg->gepg_uplink_sw_if_index);
296   mp->epg.epg_id = ntohl (gepg->gepg_id);
297   mp->epg.bd_id = ntohl (gepg->gepg_bd);
298   mp->epg.ip4_table_id = ntohl (gepg->gepg_rd[FIB_PROTOCOL_IP4]);
299   mp->epg.ip6_table_id = ntohl (gepg->gepg_rd[FIB_PROTOCOL_IP6]);
300
301   vl_api_send_msg (ctx->reg, (u8 *) mp);
302
303   return (1);
304 }
305
306 static void
307 vl_api_gbp_endpoint_group_dump_t_handler (vl_api_gbp_endpoint_group_dump_t *
308                                           mp)
309 {
310   vl_api_registration_t *reg;
311
312   reg = vl_api_client_index_to_registration (mp->client_index);
313   if (!reg)
314     return;
315
316   gbp_walk_ctx_t ctx = {
317     .reg = reg,
318     .context = mp->context,
319   };
320
321   gbp_endpoint_group_walk (gbp_endpoint_group_send_details, &ctx);
322 }
323
324 static void
325 vl_api_gbp_recirc_add_del_t_handler (vl_api_gbp_recirc_add_del_t * mp)
326 {
327   vl_api_gbp_recirc_add_del_reply_t *rmp;
328   u32 sw_if_index;
329   int rv = 0;
330
331   sw_if_index = ntohl (mp->recirc.sw_if_index);
332   if (!vnet_sw_if_index_is_api_valid (sw_if_index))
333     goto bad_sw_if_index;
334
335   if (mp->is_add)
336     gbp_recirc_add (sw_if_index,
337                     ntohl (mp->recirc.epg_id), mp->recirc.is_ext);
338   else
339     gbp_recirc_delete (sw_if_index);
340
341   BAD_SW_IF_INDEX_LABEL;
342
343   REPLY_MACRO (VL_API_GBP_RECIRC_ADD_DEL_REPLY + GBP_MSG_BASE);
344 }
345
346 static int
347 gbp_recirc_send_details (gbp_recirc_t * gr, void *args)
348 {
349   vl_api_gbp_recirc_details_t *mp;
350   gbp_walk_ctx_t *ctx;
351
352   ctx = args;
353   mp = vl_msg_api_alloc (sizeof (*mp));
354   if (!mp)
355     return 1;
356
357   memset (mp, 0, sizeof (*mp));
358   mp->_vl_msg_id = ntohs (VL_API_GBP_RECIRC_DETAILS + GBP_MSG_BASE);
359   mp->context = ctx->context;
360
361   mp->recirc.epg_id = ntohl (gr->gr_epg);
362   mp->recirc.sw_if_index = ntohl (gr->gr_sw_if_index);
363   mp->recirc.is_ext = ntohl (gr->gr_is_ext);
364
365   vl_api_send_msg (ctx->reg, (u8 *) mp);
366
367   return (1);
368 }
369
370 static void
371 vl_api_gbp_recirc_dump_t_handler (vl_api_gbp_recirc_dump_t * mp)
372 {
373   vl_api_registration_t *reg;
374
375   reg = vl_api_client_index_to_registration (mp->client_index);
376   if (!reg)
377     return;
378
379   gbp_walk_ctx_t ctx = {
380     .reg = reg,
381     .context = mp->context,
382   };
383
384   gbp_recirc_walk (gbp_recirc_send_details, &ctx);
385 }
386
387 static void
388 vl_api_gbp_contract_add_del_t_handler (vl_api_gbp_contract_add_del_t * mp)
389 {
390   vl_api_gbp_contract_add_del_reply_t *rmp;
391   int rv = 0;
392
393   if (mp->is_add)
394     gbp_contract_update (ntohl (mp->contract.src_epg),
395                          ntohl (mp->contract.dst_epg),
396                          ntohl (mp->contract.acl_index));
397   else
398     gbp_contract_delete (ntohl (mp->contract.src_epg),
399                          ntohl (mp->contract.dst_epg));
400
401   REPLY_MACRO (VL_API_GBP_CONTRACT_ADD_DEL_REPLY + GBP_MSG_BASE);
402 }
403
404 static int
405 gbp_contract_send_details (gbp_contract_t * gbpc, void *args)
406 {
407   vl_api_gbp_contract_details_t *mp;
408   gbp_walk_ctx_t *ctx;
409
410   ctx = args;
411   mp = vl_msg_api_alloc (sizeof (*mp));
412   if (!mp)
413     return 1;
414
415   memset (mp, 0, sizeof (*mp));
416   mp->_vl_msg_id = ntohs (VL_API_GBP_CONTRACT_DETAILS + GBP_MSG_BASE);
417   mp->context = ctx->context;
418
419   mp->contract.src_epg = ntohl (gbpc->gc_key.gck_src);
420   mp->contract.dst_epg = ntohl (gbpc->gc_key.gck_dst);
421   mp->contract.acl_index = ntohl (gbpc->gc_acl_index);
422
423   vl_api_send_msg (ctx->reg, (u8 *) mp);
424
425   return (1);
426 }
427
428 static void
429 vl_api_gbp_contract_dump_t_handler (vl_api_gbp_contract_dump_t * mp)
430 {
431   vl_api_registration_t *reg;
432
433   reg = vl_api_client_index_to_registration (mp->client_index);
434   if (!reg)
435     return;
436
437   gbp_walk_ctx_t ctx = {
438     .reg = reg,
439     .context = mp->context,
440   };
441
442   gbp_contract_walk (gbp_contract_send_details, &ctx);
443 }
444
445 /*
446  * gbp_api_hookup
447  * Add vpe's API message handlers to the table.
448  * vlib has alread mapped shared memory and
449  * added the client registration handlers.
450  * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
451  */
452 #define vl_msg_name_crc_list
453 #include <gbp/gbp_all_api_h.h>
454 #undef vl_msg_name_crc_list
455
456 static void
457 setup_message_id_table (api_main_t * am)
458 {
459 #define _(id,n,crc)                                     \
460   vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + GBP_MSG_BASE);
461   foreach_vl_msg_name_crc_gbp;
462 #undef _
463 }
464
465 static void
466 gbp_api_hookup (vlib_main_t * vm)
467 {
468 #define _(N,n)                                                  \
469     vl_msg_api_set_handlers(VL_API_##N + GBP_MSG_BASE,          \
470                             #n,                                 \
471                             vl_api_##n##_t_handler,             \
472                             vl_noop_handler,                    \
473                             vl_api_##n##_t_endian,              \
474                             vl_api_##n##_t_print,               \
475                             sizeof(vl_api_##n##_t), 1);
476   foreach_gbp_api_msg;
477 #undef _
478 }
479
480 static clib_error_t *
481 gbp_init (vlib_main_t * vm)
482 {
483   api_main_t *am = &api_main;
484   gbp_main_t *gbpm = &gbp_main;
485   u8 *name = format (0, "gbp_%08x%c", api_version, 0);
486
487   /* Ask for a correctly-sized block of API message decode slots */
488   gbpm->msg_id_base = vl_msg_api_get_msg_ids ((char *) name,
489                                               VL_MSG_FIRST_AVAILABLE);
490
491   gbp_api_hookup (vm);
492
493   /* Add our API messages to the global name_crc hash table */
494   setup_message_id_table (am);
495
496   vec_free (name);
497   return (NULL);
498 }
499
500 VLIB_API_INIT_FUNCTION (gbp_init);
501
502 /* *INDENT-OFF* */
503 VLIB_PLUGIN_REGISTER () = {
504     .version = VPP_BUILD_VER,
505     .description = "Group Based Policy",
506 };
507 /* *INDENT-ON* */
508
509
510 /*
511  * fd.io coding-style-patch-verification: ON
512  *
513  * Local Variables:
514  * eval: (c-set-style "gnu")
515  * End:
516  */