bbcd2d4e1d38836ac98626a155ba278eba36374c
[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 <vnet/ip/ip_types_api.h>
24 #include <vnet/ethernet/ethernet_types_api.h>
25 #include <vpp/app/version.h>
26
27 #include <gbp/gbp.h>
28 #include <gbp/gbp_learn.h>
29 #include <gbp/gbp_itf.h>
30 #include <gbp/gbp_vxlan.h>
31 #include <gbp/gbp_bridge_domain.h>
32 #include <gbp/gbp_route_domain.h>
33 #include <gbp/gbp_ext_itf.h>
34 #include <gbp/gbp_contract.h>
35
36 #include <vlibapi/api.h>
37 #include <vlibmemory/api.h>
38
39 /* define message IDs */
40 #include <gbp/gbp.api_enum.h>
41 #include <gbp/gbp.api_types.h>
42 #include <vnet/format_fns.h>
43 #include <vlibapi/api_helper_macros.h>
44 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
45 #include "gbp_api_print.h"
46
47 gbp_main_t gbp_main;
48
49 static u16 msg_id_base;
50
51 #define GBP_MSG_BASE msg_id_base
52
53 static gbp_endpoint_flags_t
54 gbp_endpoint_flags_decode (vl_api_gbp_endpoint_flags_t v)
55 {
56   gbp_endpoint_flags_t f = GBP_ENDPOINT_FLAG_NONE;
57
58   v = ntohl (v);
59
60   if (v & GBP_API_ENDPOINT_FLAG_BOUNCE)
61     f |= GBP_ENDPOINT_FLAG_BOUNCE;
62   if (v & GBP_API_ENDPOINT_FLAG_REMOTE)
63     f |= GBP_ENDPOINT_FLAG_REMOTE;
64   if (v & GBP_API_ENDPOINT_FLAG_LEARNT)
65     f |= GBP_ENDPOINT_FLAG_LEARNT;
66   if (v & GBP_API_ENDPOINT_FLAG_EXTERNAL)
67     f |= GBP_ENDPOINT_FLAG_EXTERNAL;
68
69   return (f);
70 }
71
72 static vl_api_gbp_endpoint_flags_t
73 gbp_endpoint_flags_encode (gbp_endpoint_flags_t f)
74 {
75   vl_api_gbp_endpoint_flags_t v = 0;
76
77
78   if (f & GBP_ENDPOINT_FLAG_BOUNCE)
79     v |= GBP_API_ENDPOINT_FLAG_BOUNCE;
80   if (f & GBP_ENDPOINT_FLAG_REMOTE)
81     v |= GBP_API_ENDPOINT_FLAG_REMOTE;
82   if (f & GBP_ENDPOINT_FLAG_LEARNT)
83     v |= GBP_API_ENDPOINT_FLAG_LEARNT;
84   if (f & GBP_ENDPOINT_FLAG_EXTERNAL)
85     v |= GBP_API_ENDPOINT_FLAG_EXTERNAL;
86
87   v = htonl (v);
88
89   return (v);
90 }
91
92 static void
93 vl_api_gbp_endpoint_add_t_handler (vl_api_gbp_endpoint_add_t * mp)
94 {
95   vl_api_gbp_endpoint_add_reply_t *rmp;
96   gbp_endpoint_flags_t gef;
97   u32 sw_if_index, handle;
98   ip46_address_t *ips;
99   mac_address_t mac;
100   int rv = 0, ii;
101
102   VALIDATE_SW_IF_INDEX (&(mp->endpoint));
103
104   gef = gbp_endpoint_flags_decode (mp->endpoint.flags), ips = NULL;
105   sw_if_index = ntohl (mp->endpoint.sw_if_index);
106
107   if (mp->endpoint.n_ips)
108     {
109       vec_validate (ips, mp->endpoint.n_ips - 1);
110
111       vec_foreach_index (ii, ips)
112       {
113         ip_address_decode (&mp->endpoint.ips[ii], &ips[ii]);
114       }
115     }
116   mac_address_decode (mp->endpoint.mac, &mac);
117
118   if (GBP_ENDPOINT_FLAG_REMOTE & gef)
119     {
120       ip46_address_t tun_src, tun_dst;
121
122       ip_address_decode (&mp->endpoint.tun.src, &tun_src);
123       ip_address_decode (&mp->endpoint.tun.dst, &tun_dst);
124
125       rv = gbp_endpoint_update_and_lock (GBP_ENDPOINT_SRC_CP,
126                                          sw_if_index, ips, &mac,
127                                          INDEX_INVALID, INDEX_INVALID,
128                                          ntohs (mp->endpoint.sclass),
129                                          gef, &tun_src, &tun_dst, &handle);
130     }
131   else
132     {
133       rv = gbp_endpoint_update_and_lock (GBP_ENDPOINT_SRC_CP,
134                                          sw_if_index, ips, &mac,
135                                          INDEX_INVALID, INDEX_INVALID,
136                                          ntohs (mp->endpoint.sclass),
137                                          gef, NULL, NULL, &handle);
138     }
139   vec_free (ips);
140   BAD_SW_IF_INDEX_LABEL;
141
142   /* *INDENT-OFF* */
143   REPLY_MACRO2 (VL_API_GBP_ENDPOINT_ADD_REPLY + GBP_MSG_BASE,
144   ({
145     rmp->handle = htonl (handle);
146   }));
147   /* *INDENT-ON* */
148 }
149
150 static void
151 vl_api_gbp_endpoint_del_t_handler (vl_api_gbp_endpoint_del_t * mp)
152 {
153   vl_api_gbp_endpoint_del_reply_t *rmp;
154   int rv = 0;
155
156   gbp_endpoint_unlock (GBP_ENDPOINT_SRC_CP, ntohl (mp->handle));
157
158   REPLY_MACRO (VL_API_GBP_ENDPOINT_DEL_REPLY + GBP_MSG_BASE);
159 }
160
161 typedef struct gbp_walk_ctx_t_
162 {
163   vl_api_registration_t *reg;
164   u32 context;
165 } gbp_walk_ctx_t;
166
167 static walk_rc_t
168 gbp_endpoint_send_details (index_t gei, void *args)
169 {
170   vl_api_gbp_endpoint_details_t *mp;
171   gbp_endpoint_loc_t *gel;
172   gbp_endpoint_fwd_t *gef;
173   gbp_endpoint_t *ge;
174   gbp_walk_ctx_t *ctx;
175   u8 n_ips, ii;
176
177   ctx = args;
178   ge = gbp_endpoint_get (gei);
179
180   n_ips = vec_len (ge->ge_key.gek_ips);
181   mp = vl_msg_api_alloc (sizeof (*mp) + (sizeof (*mp->endpoint.ips) * n_ips));
182   if (!mp)
183     return 1;
184
185   clib_memset (mp, 0, sizeof (*mp));
186   mp->_vl_msg_id = ntohs (VL_API_GBP_ENDPOINT_DETAILS + GBP_MSG_BASE);
187   mp->context = ctx->context;
188
189   gel = &ge->ge_locs[0];
190   gef = &ge->ge_fwd;
191
192   if (gbp_endpoint_is_remote (ge))
193     {
194       mp->endpoint.sw_if_index = ntohl (gel->tun.gel_parent_sw_if_index);
195       ip_address_encode (&gel->tun.gel_src, IP46_TYPE_ANY,
196                          &mp->endpoint.tun.src);
197       ip_address_encode (&gel->tun.gel_dst, IP46_TYPE_ANY,
198                          &mp->endpoint.tun.dst);
199     }
200   else
201     {
202       mp->endpoint.sw_if_index =
203         ntohl (gbp_itf_get_sw_if_index (gef->gef_itf));
204     }
205   mp->endpoint.sclass = ntohs (ge->ge_fwd.gef_sclass);
206   mp->endpoint.n_ips = n_ips;
207   mp->endpoint.flags = gbp_endpoint_flags_encode (gef->gef_flags);
208   mp->handle = htonl (gei);
209   mp->age =
210     clib_host_to_net_f64 (vlib_time_now (vlib_get_main ()) -
211                           ge->ge_last_time);
212   mac_address_encode (&ge->ge_key.gek_mac, mp->endpoint.mac);
213
214   vec_foreach_index (ii, ge->ge_key.gek_ips)
215   {
216     ip_address_encode (&ge->ge_key.gek_ips[ii].fp_addr,
217                        IP46_TYPE_ANY, &mp->endpoint.ips[ii]);
218   }
219
220   vl_api_send_msg (ctx->reg, (u8 *) mp);
221
222   return (WALK_CONTINUE);
223 }
224
225 static void
226 vl_api_gbp_endpoint_dump_t_handler (vl_api_gbp_endpoint_dump_t * mp)
227 {
228   vl_api_registration_t *reg;
229
230   reg = vl_api_client_index_to_registration (mp->client_index);
231   if (!reg)
232     return;
233
234   gbp_walk_ctx_t ctx = {
235     .reg = reg,
236     .context = mp->context,
237   };
238
239   gbp_endpoint_walk (gbp_endpoint_send_details, &ctx);
240 }
241
242 static void
243 gbp_retention_decode (const vl_api_gbp_endpoint_retention_t * in,
244                       gbp_endpoint_retention_t * out)
245 {
246   out->remote_ep_timeout = ntohl (in->remote_ep_timeout);
247 }
248
249 static void
250   vl_api_gbp_endpoint_group_add_t_handler
251   (vl_api_gbp_endpoint_group_add_t * mp)
252 {
253   vl_api_gbp_endpoint_group_add_reply_t *rmp;
254   gbp_endpoint_retention_t retention;
255   int rv = 0;
256
257   gbp_retention_decode (&mp->epg.retention, &retention);
258
259   rv = gbp_endpoint_group_add_and_lock (ntohl (mp->epg.vnid),
260                                         ntohs (mp->epg.sclass),
261                                         ntohl (mp->epg.bd_id),
262                                         ntohl (mp->epg.rd_id),
263                                         ntohl (mp->epg.uplink_sw_if_index),
264                                         &retention);
265
266   REPLY_MACRO (VL_API_GBP_ENDPOINT_GROUP_ADD_REPLY + GBP_MSG_BASE);
267 }
268
269 static void
270   vl_api_gbp_endpoint_group_del_t_handler
271   (vl_api_gbp_endpoint_group_del_t * mp)
272 {
273   vl_api_gbp_endpoint_group_del_reply_t *rmp;
274   int rv = 0;
275
276   rv = gbp_endpoint_group_delete (ntohs (mp->sclass));
277
278   REPLY_MACRO (VL_API_GBP_ENDPOINT_GROUP_DEL_REPLY + GBP_MSG_BASE);
279 }
280
281 static gbp_bridge_domain_flags_t
282 gbp_bridge_domain_flags_from_api (vl_api_gbp_bridge_domain_flags_t a)
283 {
284   gbp_bridge_domain_flags_t g;
285
286   g = GBP_BD_FLAG_NONE;
287   a = clib_net_to_host_u32 (a);
288
289   if (a & GBP_BD_API_FLAG_DO_NOT_LEARN)
290     g |= GBP_BD_FLAG_DO_NOT_LEARN;
291   if (a & GBP_BD_API_FLAG_UU_FWD_DROP)
292     g |= GBP_BD_FLAG_UU_FWD_DROP;
293   if (a & GBP_BD_API_FLAG_MCAST_DROP)
294     g |= GBP_BD_FLAG_MCAST_DROP;
295   if (a & GBP_BD_API_FLAG_UCAST_ARP)
296     g |= GBP_BD_FLAG_UCAST_ARP;
297
298   return (g);
299 }
300
301 static void
302 vl_api_gbp_bridge_domain_add_t_handler (vl_api_gbp_bridge_domain_add_t * mp)
303 {
304   vl_api_gbp_bridge_domain_add_reply_t *rmp;
305   int rv = 0;
306
307   rv = gbp_bridge_domain_add_and_lock (ntohl (mp->bd.bd_id),
308                                        ntohl (mp->bd.rd_id),
309                                        gbp_bridge_domain_flags_from_api
310                                        (mp->bd.flags),
311                                        ntohl (mp->bd.bvi_sw_if_index),
312                                        ntohl (mp->bd.uu_fwd_sw_if_index),
313                                        ntohl (mp->bd.bm_flood_sw_if_index));
314
315   REPLY_MACRO (VL_API_GBP_BRIDGE_DOMAIN_ADD_REPLY + GBP_MSG_BASE);
316 }
317
318 static void
319 vl_api_gbp_bridge_domain_del_t_handler (vl_api_gbp_bridge_domain_del_t * mp)
320 {
321   vl_api_gbp_bridge_domain_del_reply_t *rmp;
322   int rv = 0;
323
324   rv = gbp_bridge_domain_delete (ntohl (mp->bd_id));
325
326   REPLY_MACRO (VL_API_GBP_BRIDGE_DOMAIN_DEL_REPLY + GBP_MSG_BASE);
327 }
328
329 static void
330 vl_api_gbp_route_domain_add_t_handler (vl_api_gbp_route_domain_add_t * mp)
331 {
332   vl_api_gbp_route_domain_add_reply_t *rmp;
333   int rv = 0;
334
335   rv = gbp_route_domain_add_and_lock (ntohl (mp->rd.rd_id),
336                                       ntohs (mp->rd.scope),
337                                       ntohl (mp->rd.ip4_table_id),
338                                       ntohl (mp->rd.ip6_table_id),
339                                       ntohl (mp->rd.ip4_uu_sw_if_index),
340                                       ntohl (mp->rd.ip6_uu_sw_if_index));
341
342   REPLY_MACRO (VL_API_GBP_ROUTE_DOMAIN_ADD_REPLY + GBP_MSG_BASE);
343 }
344
345 static void
346 vl_api_gbp_route_domain_del_t_handler (vl_api_gbp_route_domain_del_t * mp)
347 {
348   vl_api_gbp_route_domain_del_reply_t *rmp;
349   int rv = 0;
350
351   rv = gbp_route_domain_delete (ntohl (mp->rd_id));
352
353   REPLY_MACRO (VL_API_GBP_ROUTE_DOMAIN_DEL_REPLY + GBP_MSG_BASE);
354 }
355
356 static int
357 gub_subnet_type_from_api (vl_api_gbp_subnet_type_t a, gbp_subnet_type_t * t)
358 {
359   a = clib_net_to_host_u32 (a);
360
361   switch (a)
362     {
363     case GBP_API_SUBNET_TRANSPORT:
364       *t = GBP_SUBNET_TRANSPORT;
365       return (0);
366     case GBP_API_SUBNET_L3_OUT:
367       *t = GBP_SUBNET_L3_OUT;
368       return (0);
369     case GBP_API_SUBNET_ANON_L3_OUT:
370       *t = GBP_SUBNET_ANON_L3_OUT;
371       return (0);
372     case GBP_API_SUBNET_STITCHED_INTERNAL:
373       *t = GBP_SUBNET_STITCHED_INTERNAL;
374       return (0);
375     case GBP_API_SUBNET_STITCHED_EXTERNAL:
376       *t = GBP_SUBNET_STITCHED_EXTERNAL;
377       return (0);
378     }
379
380   return (-1);
381 }
382
383 static void
384 vl_api_gbp_subnet_add_del_t_handler (vl_api_gbp_subnet_add_del_t * mp)
385 {
386   vl_api_gbp_subnet_add_del_reply_t *rmp;
387   gbp_subnet_type_t type;
388   fib_prefix_t pfx;
389   int rv = 0;
390
391   ip_prefix_decode (&mp->subnet.prefix, &pfx);
392
393   rv = gub_subnet_type_from_api (mp->subnet.type, &type);
394
395   if (0 != rv)
396     goto out;
397
398   if (mp->is_add)
399     rv = gbp_subnet_add (ntohl (mp->subnet.rd_id),
400                          &pfx, type,
401                          ntohl (mp->subnet.sw_if_index),
402                          ntohs (mp->subnet.sclass));
403   else
404     rv = gbp_subnet_del (ntohl (mp->subnet.rd_id), &pfx);
405
406 out:
407   REPLY_MACRO (VL_API_GBP_SUBNET_ADD_DEL_REPLY + GBP_MSG_BASE);
408 }
409
410 static vl_api_gbp_subnet_type_t
411 gub_subnet_type_to_api (gbp_subnet_type_t t)
412 {
413   vl_api_gbp_subnet_type_t a = 0;
414
415   switch (t)
416     {
417     case GBP_SUBNET_TRANSPORT:
418       a = GBP_API_SUBNET_TRANSPORT;
419       break;
420     case GBP_SUBNET_STITCHED_INTERNAL:
421       a = GBP_API_SUBNET_STITCHED_INTERNAL;
422       break;
423     case GBP_SUBNET_STITCHED_EXTERNAL:
424       a = GBP_API_SUBNET_STITCHED_EXTERNAL;
425       break;
426     case GBP_SUBNET_L3_OUT:
427       a = GBP_API_SUBNET_L3_OUT;
428       break;
429     case GBP_SUBNET_ANON_L3_OUT:
430       a = GBP_API_SUBNET_ANON_L3_OUT;
431       break;
432     }
433
434   a = clib_host_to_net_u32 (a);
435
436   return (a);
437 }
438
439 static walk_rc_t
440 gbp_subnet_send_details (u32 rd_id,
441                          const fib_prefix_t * pfx,
442                          gbp_subnet_type_t type,
443                          u32 sw_if_index, sclass_t sclass, void *args)
444 {
445   vl_api_gbp_subnet_details_t *mp;
446   gbp_walk_ctx_t *ctx;
447
448   ctx = args;
449   mp = vl_msg_api_alloc (sizeof (*mp));
450   if (!mp)
451     return 1;
452
453   clib_memset (mp, 0, sizeof (*mp));
454   mp->_vl_msg_id = ntohs (VL_API_GBP_SUBNET_DETAILS + GBP_MSG_BASE);
455   mp->context = ctx->context;
456
457   mp->subnet.type = gub_subnet_type_to_api (type);
458   mp->subnet.sw_if_index = ntohl (sw_if_index);
459   mp->subnet.sclass = ntohs (sclass);
460   mp->subnet.rd_id = ntohl (rd_id);
461   ip_prefix_encode (pfx, &mp->subnet.prefix);
462
463   vl_api_send_msg (ctx->reg, (u8 *) mp);
464
465   return (WALK_CONTINUE);
466 }
467
468 static void
469 vl_api_gbp_subnet_dump_t_handler (vl_api_gbp_subnet_dump_t * mp)
470 {
471   vl_api_registration_t *reg;
472
473   reg = vl_api_client_index_to_registration (mp->client_index);
474   if (!reg)
475     return;
476
477   gbp_walk_ctx_t ctx = {
478     .reg = reg,
479     .context = mp->context,
480   };
481
482   gbp_subnet_walk (gbp_subnet_send_details, &ctx);
483 }
484
485 static int
486 gbp_endpoint_group_send_details (gbp_endpoint_group_t * gg, void *args)
487 {
488   vl_api_gbp_endpoint_group_details_t *mp;
489   gbp_walk_ctx_t *ctx;
490
491   ctx = args;
492   mp = vl_msg_api_alloc (sizeof (*mp));
493   if (!mp)
494     return 1;
495
496   clib_memset (mp, 0, sizeof (*mp));
497   mp->_vl_msg_id = ntohs (VL_API_GBP_ENDPOINT_GROUP_DETAILS + GBP_MSG_BASE);
498   mp->context = ctx->context;
499
500   mp->epg.uplink_sw_if_index = ntohl (gg->gg_uplink_sw_if_index);
501   mp->epg.vnid = ntohl (gg->gg_vnid);
502   mp->epg.sclass = ntohs (gg->gg_sclass);
503   mp->epg.bd_id = ntohl (gbp_endpoint_group_get_bd_id (gg));
504   mp->epg.rd_id = ntohl (gbp_route_domain_get_rd_id (gg->gg_rd));
505
506   vl_api_send_msg (ctx->reg, (u8 *) mp);
507
508   return (1);
509 }
510
511 static void
512 vl_api_gbp_endpoint_group_dump_t_handler (vl_api_gbp_endpoint_group_dump_t *
513                                           mp)
514 {
515   vl_api_registration_t *reg;
516
517   reg = vl_api_client_index_to_registration (mp->client_index);
518   if (!reg)
519     return;
520
521   gbp_walk_ctx_t ctx = {
522     .reg = reg,
523     .context = mp->context,
524   };
525
526   gbp_endpoint_group_walk (gbp_endpoint_group_send_details, &ctx);
527 }
528
529 static int
530 gbp_bridge_domain_send_details (gbp_bridge_domain_t * gb, void *args)
531 {
532   vl_api_gbp_bridge_domain_details_t *mp;
533   gbp_route_domain_t *gr;
534   gbp_walk_ctx_t *ctx;
535
536   ctx = args;
537   mp = vl_msg_api_alloc (sizeof (*mp));
538   if (!mp)
539     return 1;
540
541   memset (mp, 0, sizeof (*mp));
542   mp->_vl_msg_id = ntohs (VL_API_GBP_BRIDGE_DOMAIN_DETAILS + GBP_MSG_BASE);
543   mp->context = ctx->context;
544
545   gr = gbp_route_domain_get (gb->gb_rdi);
546
547   mp->bd.bd_id = ntohl (gb->gb_bd_id);
548   mp->bd.rd_id = ntohl (gr->grd_id);
549   mp->bd.bvi_sw_if_index = ntohl (gb->gb_bvi_sw_if_index);
550   mp->bd.uu_fwd_sw_if_index = ntohl (gb->gb_uu_fwd_sw_if_index);
551   mp->bd.bm_flood_sw_if_index =
552     ntohl (gbp_itf_get_sw_if_index (gb->gb_bm_flood_itf));
553
554   vl_api_send_msg (ctx->reg, (u8 *) mp);
555
556   return (1);
557 }
558
559 static void
560 vl_api_gbp_bridge_domain_dump_t_handler (vl_api_gbp_bridge_domain_dump_t * mp)
561 {
562   vl_api_registration_t *reg;
563
564   reg = vl_api_client_index_to_registration (mp->client_index);
565   if (!reg)
566     return;
567
568   gbp_walk_ctx_t ctx = {
569     .reg = reg,
570     .context = mp->context,
571   };
572
573   gbp_bridge_domain_walk (gbp_bridge_domain_send_details, &ctx);
574 }
575
576 static int
577 gbp_route_domain_send_details (gbp_route_domain_t * grd, void *args)
578 {
579   vl_api_gbp_route_domain_details_t *mp;
580   gbp_walk_ctx_t *ctx;
581
582   ctx = args;
583   mp = vl_msg_api_alloc (sizeof (*mp));
584   if (!mp)
585     return 1;
586
587   memset (mp, 0, sizeof (*mp));
588   mp->_vl_msg_id = ntohs (VL_API_GBP_ROUTE_DOMAIN_DETAILS + GBP_MSG_BASE);
589   mp->context = ctx->context;
590
591   mp->rd.rd_id = ntohl (grd->grd_id);
592   mp->rd.ip4_uu_sw_if_index =
593     ntohl (grd->grd_uu_sw_if_index[FIB_PROTOCOL_IP4]);
594   mp->rd.ip6_uu_sw_if_index =
595     ntohl (grd->grd_uu_sw_if_index[FIB_PROTOCOL_IP6]);
596
597   vl_api_send_msg (ctx->reg, (u8 *) mp);
598
599   return (1);
600 }
601
602 static void
603 vl_api_gbp_route_domain_dump_t_handler (vl_api_gbp_route_domain_dump_t * mp)
604 {
605   vl_api_registration_t *reg;
606
607   reg = vl_api_client_index_to_registration (mp->client_index);
608   if (!reg)
609     return;
610
611   gbp_walk_ctx_t ctx = {
612     .reg = reg,
613     .context = mp->context,
614   };
615
616   gbp_route_domain_walk (gbp_route_domain_send_details, &ctx);
617 }
618
619 static void
620 vl_api_gbp_recirc_add_del_t_handler (vl_api_gbp_recirc_add_del_t * mp)
621 {
622   vl_api_gbp_recirc_add_del_reply_t *rmp;
623   u32 sw_if_index;
624   int rv = 0;
625
626   sw_if_index = ntohl (mp->recirc.sw_if_index);
627   if (!vnet_sw_if_index_is_api_valid (sw_if_index))
628     goto bad_sw_if_index;
629
630   if (mp->is_add)
631     rv = gbp_recirc_add (sw_if_index,
632                          ntohs (mp->recirc.sclass), mp->recirc.is_ext);
633   else
634     rv = gbp_recirc_delete (sw_if_index);
635
636   BAD_SW_IF_INDEX_LABEL;
637
638   REPLY_MACRO (VL_API_GBP_RECIRC_ADD_DEL_REPLY + GBP_MSG_BASE);
639 }
640
641 static walk_rc_t
642 gbp_recirc_send_details (gbp_recirc_t * gr, void *args)
643 {
644   vl_api_gbp_recirc_details_t *mp;
645   gbp_walk_ctx_t *ctx;
646
647   ctx = args;
648   mp = vl_msg_api_alloc (sizeof (*mp));
649   if (!mp)
650     return (WALK_STOP);
651
652   clib_memset (mp, 0, sizeof (*mp));
653   mp->_vl_msg_id = ntohs (VL_API_GBP_RECIRC_DETAILS + GBP_MSG_BASE);
654   mp->context = ctx->context;
655
656   mp->recirc.sclass = ntohs (gr->gr_sclass);
657   mp->recirc.sw_if_index = ntohl (gr->gr_sw_if_index);
658   mp->recirc.is_ext = gr->gr_is_ext;
659
660   vl_api_send_msg (ctx->reg, (u8 *) mp);
661
662   return (WALK_CONTINUE);
663 }
664
665 static void
666 vl_api_gbp_recirc_dump_t_handler (vl_api_gbp_recirc_dump_t * mp)
667 {
668   vl_api_registration_t *reg;
669
670   reg = vl_api_client_index_to_registration (mp->client_index);
671   if (!reg)
672     return;
673
674   gbp_walk_ctx_t ctx = {
675     .reg = reg,
676     .context = mp->context,
677   };
678
679   gbp_recirc_walk (gbp_recirc_send_details, &ctx);
680 }
681
682 static void
683 vl_api_gbp_ext_itf_add_del_t_handler (vl_api_gbp_ext_itf_add_del_t * mp)
684 {
685   vl_api_gbp_ext_itf_add_del_reply_t *rmp;
686   u32 sw_if_index = ~0;
687   vl_api_gbp_ext_itf_t *ext_itf;
688   int rv = 0;
689
690   ext_itf = &mp->ext_itf;
691   if (ext_itf)
692     sw_if_index = ntohl (ext_itf->sw_if_index);
693
694   if (!vnet_sw_if_index_is_api_valid (sw_if_index))
695     goto bad_sw_if_index;
696
697   if (mp->is_add)
698     rv = gbp_ext_itf_add (sw_if_index,
699                           ntohl (ext_itf->bd_id), ntohl (ext_itf->rd_id),
700                           ntohl (ext_itf->flags));
701   else
702     rv = gbp_ext_itf_delete (sw_if_index);
703
704   BAD_SW_IF_INDEX_LABEL;
705
706   REPLY_MACRO (VL_API_GBP_EXT_ITF_ADD_DEL_REPLY + GBP_MSG_BASE);
707 }
708
709 static walk_rc_t
710 gbp_ext_itf_send_details (gbp_ext_itf_t * gx, void *args)
711 {
712   vl_api_gbp_ext_itf_details_t *mp;
713   gbp_walk_ctx_t *ctx;
714
715   ctx = args;
716   mp = vl_msg_api_alloc (sizeof (*mp));
717   if (!mp)
718     return (WALK_STOP);
719
720   clib_memset (mp, 0, sizeof (*mp));
721   mp->_vl_msg_id = ntohs (VL_API_GBP_EXT_ITF_DETAILS + GBP_MSG_BASE);
722   mp->context = ctx->context;
723
724   mp->ext_itf.flags = ntohl (gx->gx_flags);
725   mp->ext_itf.bd_id = ntohl (gbp_bridge_domain_get_bd_id (gx->gx_bd));
726   mp->ext_itf.rd_id = ntohl (gbp_route_domain_get_rd_id (gx->gx_rd));
727   mp->ext_itf.sw_if_index = ntohl (gbp_itf_get_sw_if_index (gx->gx_itf));
728
729   vl_api_send_msg (ctx->reg, (u8 *) mp);
730
731   return (WALK_CONTINUE);
732 }
733
734 static void
735 vl_api_gbp_ext_itf_dump_t_handler (vl_api_gbp_ext_itf_dump_t * mp)
736 {
737   vl_api_registration_t *reg;
738
739   reg = vl_api_client_index_to_registration (mp->client_index);
740   if (!reg)
741     return;
742
743   gbp_walk_ctx_t ctx = {
744     .reg = reg,
745     .context = mp->context,
746   };
747
748   gbp_ext_itf_walk (gbp_ext_itf_send_details, &ctx);
749 }
750
751 static int
752 gbp_contract_rule_action_deocde (vl_api_gbp_rule_action_t in,
753                                  gbp_rule_action_t * out)
754 {
755   in = clib_net_to_host_u32 (in);
756
757   switch (in)
758     {
759     case GBP_API_RULE_PERMIT:
760       *out = GBP_RULE_PERMIT;
761       return (0);
762     case GBP_API_RULE_DENY:
763       *out = GBP_RULE_DENY;
764       return (0);
765     case GBP_API_RULE_REDIRECT:
766       *out = GBP_RULE_REDIRECT;
767       return (0);
768     }
769
770   return (-1);
771 }
772
773 static int
774 gbp_hash_mode_decode (vl_api_gbp_hash_mode_t in, gbp_hash_mode_t * out)
775 {
776   in = clib_net_to_host_u32 (in);
777
778   switch (in)
779     {
780     case GBP_API_HASH_MODE_SRC_IP:
781       *out = GBP_HASH_MODE_SRC_IP;
782       return (0);
783     case GBP_API_HASH_MODE_DST_IP:
784       *out = GBP_HASH_MODE_DST_IP;
785       return (0);
786     case GBP_API_HASH_MODE_SYMMETRIC:
787       *out = GBP_HASH_MODE_SYMMETRIC;
788       return (0);
789     }
790
791   return (-2);
792 }
793
794 static int
795 gbp_next_hop_decode (const vl_api_gbp_next_hop_t * in, index_t * gnhi)
796 {
797   ip46_address_t ip;
798   mac_address_t mac;
799   index_t grd, gbd;
800
801   gbd = gbp_bridge_domain_find_and_lock (ntohl (in->bd_id));
802
803   if (INDEX_INVALID == gbd)
804     return (VNET_API_ERROR_BD_NOT_MODIFIABLE);
805
806   grd = gbp_route_domain_find_and_lock (ntohl (in->rd_id));
807
808   if (INDEX_INVALID == grd)
809     return (VNET_API_ERROR_NO_SUCH_FIB);
810
811   ip_address_decode (&in->ip, &ip);
812   mac_address_decode (in->mac, &mac);
813
814   *gnhi = gbp_next_hop_alloc (&ip, grd, &mac, gbd);
815
816   return (0);
817 }
818
819 static int
820 gbp_next_hop_set_decode (const vl_api_gbp_next_hop_set_t * in,
821                          gbp_hash_mode_t * hash_mode, index_t ** out)
822 {
823
824   index_t *gnhis = NULL;
825   int rv;
826   u8 ii;
827
828   rv = gbp_hash_mode_decode (in->hash_mode, hash_mode);
829
830   if (0 != rv)
831     return rv;
832
833   vec_validate (gnhis, in->n_nhs - 1);
834
835   for (ii = 0; ii < in->n_nhs; ii++)
836     {
837       rv = gbp_next_hop_decode (&in->nhs[ii], &gnhis[ii]);
838
839       if (0 != rv)
840         {
841           vec_free (gnhis);
842           break;
843         }
844     }
845
846   *out = gnhis;
847   return (rv);
848 }
849
850 static int
851 gbp_contract_rule_decode (const vl_api_gbp_rule_t * in, index_t * gui)
852 {
853   gbp_hash_mode_t hash_mode;
854   gbp_rule_action_t action;
855   index_t *nhs = NULL;
856   int rv;
857
858   rv = gbp_contract_rule_action_deocde (in->action, &action);
859
860   if (0 != rv)
861     return rv;
862
863   if (GBP_RULE_REDIRECT == action)
864     {
865       rv = gbp_next_hop_set_decode (&in->nh_set, &hash_mode, &nhs);
866
867       if (0 != rv)
868         return (rv);
869     }
870   else
871     {
872       hash_mode = GBP_HASH_MODE_SRC_IP;
873     }
874
875   *gui = gbp_rule_alloc (action, hash_mode, nhs);
876
877   return (rv);
878 }
879
880 static int
881 gbp_contract_rules_decode (u8 n_rules,
882                            const vl_api_gbp_rule_t * rules, index_t ** out)
883 {
884   index_t *guis = NULL;
885   int rv;
886   u8 ii;
887
888   if (0 == n_rules)
889     {
890       *out = NULL;
891       return (0);
892     }
893
894   vec_validate (guis, n_rules - 1);
895
896   for (ii = 0; ii < n_rules; ii++)
897     {
898       rv = gbp_contract_rule_decode (&rules[ii], &guis[ii]);
899
900       if (0 != rv)
901         {
902           index_t *gui;
903           vec_foreach (gui, guis) gbp_rule_free (*gui);
904           vec_free (guis);
905           return (rv);
906         }
907     }
908
909   *out = guis;
910   return (rv);
911 }
912
913 static void
914 vl_api_gbp_contract_add_del_t_handler (vl_api_gbp_contract_add_del_t * mp)
915 {
916   vl_api_gbp_contract_add_del_reply_t *rmp;
917   u16 *allowed_ethertypes;
918   u32 stats_index = ~0;
919   index_t *rules;
920   int ii, rv = 0;
921   u8 n_et;
922
923   if (mp->is_add)
924     {
925       rv = gbp_contract_rules_decode (mp->contract.n_rules,
926                                       mp->contract.rules, &rules);
927       if (0 != rv)
928         goto out;
929
930       allowed_ethertypes = NULL;
931
932       /*
933        * allowed ether types
934        */
935       n_et = mp->contract.n_ether_types;
936       vec_validate (allowed_ethertypes, n_et - 1);
937
938       for (ii = 0; ii < n_et; ii++)
939         {
940           /* leave the ether types in network order */
941           allowed_ethertypes[ii] = mp->contract.allowed_ethertypes[ii];
942         }
943
944       rv = gbp_contract_update (ntohs (mp->contract.scope),
945                                 ntohs (mp->contract.sclass),
946                                 ntohs (mp->contract.dclass),
947                                 ntohl (mp->contract.acl_index),
948                                 rules, allowed_ethertypes, &stats_index);
949     }
950   else
951     rv = gbp_contract_delete (ntohs (mp->contract.scope),
952                               ntohs (mp->contract.sclass),
953                               ntohs (mp->contract.dclass));
954
955 out:
956   /* *INDENT-OFF* */
957   REPLY_MACRO2 (VL_API_GBP_CONTRACT_ADD_DEL_REPLY + GBP_MSG_BASE,
958   ({
959     rmp->stats_index = htonl (stats_index);
960   }));
961   /* *INDENT-ON* */
962 }
963
964 static int
965 gbp_contract_send_details (gbp_contract_t * gbpc, void *args)
966 {
967   vl_api_gbp_contract_details_t *mp;
968   gbp_walk_ctx_t *ctx;
969
970   ctx = args;
971   mp = vl_msg_api_alloc (sizeof (*mp));
972   if (!mp)
973     return 1;
974
975   clib_memset (mp, 0, sizeof (*mp));
976   mp->_vl_msg_id = ntohs (VL_API_GBP_CONTRACT_DETAILS + GBP_MSG_BASE);
977   mp->context = ctx->context;
978
979   mp->contract.sclass = ntohs (gbpc->gc_key.gck_src);
980   mp->contract.dclass = ntohs (gbpc->gc_key.gck_dst);
981   mp->contract.acl_index = ntohl (gbpc->gc_acl_index);
982   mp->contract.scope = ntohs (gbpc->gc_key.gck_scope);
983
984   vl_api_send_msg (ctx->reg, (u8 *) mp);
985
986   return (1);
987 }
988
989 static void
990 vl_api_gbp_contract_dump_t_handler (vl_api_gbp_contract_dump_t * mp)
991 {
992   vl_api_registration_t *reg;
993
994   reg = vl_api_client_index_to_registration (mp->client_index);
995   if (!reg)
996     return;
997
998   gbp_walk_ctx_t ctx = {
999     .reg = reg,
1000     .context = mp->context,
1001   };
1002
1003   gbp_contract_walk (gbp_contract_send_details, &ctx);
1004 }
1005
1006 static int
1007 gbp_vxlan_tunnel_mode_2_layer (vl_api_gbp_vxlan_tunnel_mode_t mode,
1008                                gbp_vxlan_tunnel_layer_t * l)
1009 {
1010   mode = clib_net_to_host_u32 (mode);
1011
1012   switch (mode)
1013     {
1014     case GBP_VXLAN_TUNNEL_MODE_L2:
1015       *l = GBP_VXLAN_TUN_L2;
1016       return (0);
1017     case GBP_VXLAN_TUNNEL_MODE_L3:
1018       *l = GBP_VXLAN_TUN_L3;
1019       return (0);
1020     }
1021   return (-1);
1022 }
1023
1024 static void
1025 vl_api_gbp_vxlan_tunnel_add_t_handler (vl_api_gbp_vxlan_tunnel_add_t * mp)
1026 {
1027   vl_api_gbp_vxlan_tunnel_add_reply_t *rmp;
1028   gbp_vxlan_tunnel_layer_t layer;
1029   ip4_address_t src;
1030   u32 sw_if_index;
1031   int rv = 0;
1032
1033   ip4_address_decode (mp->tunnel.src, &src);
1034   rv = gbp_vxlan_tunnel_mode_2_layer (mp->tunnel.mode, &layer);
1035
1036   if (0 != rv)
1037     goto out;
1038
1039   rv = gbp_vxlan_tunnel_add (ntohl (mp->tunnel.vni),
1040                              layer,
1041                              ntohl (mp->tunnel.bd_rd_id), &src, &sw_if_index);
1042
1043 out:
1044   /* *INDENT-OFF* */
1045   REPLY_MACRO2 (VL_API_GBP_VXLAN_TUNNEL_ADD_REPLY + GBP_MSG_BASE,
1046   ({
1047     rmp->sw_if_index = htonl (sw_if_index);
1048   }));
1049   /* *INDENT-ON* */
1050 }
1051
1052 static void
1053 vl_api_gbp_vxlan_tunnel_del_t_handler (vl_api_gbp_vxlan_tunnel_add_t * mp)
1054 {
1055   vl_api_gbp_vxlan_tunnel_del_reply_t *rmp;
1056   int rv = 0;
1057
1058   rv = gbp_vxlan_tunnel_del (ntohl (mp->tunnel.vni));
1059
1060   REPLY_MACRO (VL_API_GBP_VXLAN_TUNNEL_DEL_REPLY + GBP_MSG_BASE);
1061 }
1062
1063 static vl_api_gbp_vxlan_tunnel_mode_t
1064 gbp_vxlan_tunnel_layer_2_mode (gbp_vxlan_tunnel_layer_t layer)
1065 {
1066   vl_api_gbp_vxlan_tunnel_mode_t mode = GBP_VXLAN_TUNNEL_MODE_L2;
1067
1068   switch (layer)
1069     {
1070     case GBP_VXLAN_TUN_L2:
1071       mode = GBP_VXLAN_TUNNEL_MODE_L2;
1072       break;
1073     case GBP_VXLAN_TUN_L3:
1074       mode = GBP_VXLAN_TUNNEL_MODE_L3;
1075       break;
1076     }
1077   mode = clib_host_to_net_u32 (mode);
1078
1079   return (mode);
1080 }
1081
1082 static walk_rc_t
1083 gbp_vxlan_tunnel_send_details (gbp_vxlan_tunnel_t * gt, void *args)
1084 {
1085   vl_api_gbp_vxlan_tunnel_details_t *mp;
1086   gbp_walk_ctx_t *ctx;
1087
1088   ctx = args;
1089   mp = vl_msg_api_alloc (sizeof (*mp));
1090   if (!mp)
1091     return 1;
1092
1093   memset (mp, 0, sizeof (*mp));
1094   mp->_vl_msg_id = htons (VL_API_GBP_VXLAN_TUNNEL_DETAILS + GBP_MSG_BASE);
1095   mp->context = ctx->context;
1096
1097   mp->tunnel.vni = htonl (gt->gt_vni);
1098   mp->tunnel.mode = gbp_vxlan_tunnel_layer_2_mode (gt->gt_layer);
1099   mp->tunnel.bd_rd_id = htonl (gt->gt_bd_rd_id);
1100
1101   vl_api_send_msg (ctx->reg, (u8 *) mp);
1102
1103   return (1);
1104 }
1105
1106 static void
1107 vl_api_gbp_vxlan_tunnel_dump_t_handler (vl_api_gbp_vxlan_tunnel_dump_t * mp)
1108 {
1109   vl_api_registration_t *reg;
1110
1111   reg = vl_api_client_index_to_registration (mp->client_index);
1112   if (!reg)
1113     return;
1114
1115   gbp_walk_ctx_t ctx = {
1116     .reg = reg,
1117     .context = mp->context,
1118   };
1119
1120   gbp_vxlan_walk (gbp_vxlan_tunnel_send_details, &ctx);
1121 }
1122
1123 #include <gbp/gbp.api.c>
1124 static clib_error_t *
1125 gbp_init (vlib_main_t * vm)
1126 {
1127   gbp_main_t *gbpm = &gbp_main;
1128
1129   gbpm->gbp_acl_user_id = ~0;
1130
1131   /* Ask for a correctly-sized block of API message decode slots */
1132   msg_id_base = setup_message_id_table ();
1133
1134   return (NULL);
1135 }
1136
1137 VLIB_API_INIT_FUNCTION (gbp_init);
1138
1139 /* *INDENT-OFF* */
1140 VLIB_PLUGIN_REGISTER () = {
1141     .version = VPP_BUILD_VER,
1142     .description = "Group Based Policy (GBP)",
1143 };
1144 /* *INDENT-ON* */
1145
1146
1147 /*
1148  * fd.io coding-style-patch-verification: ON
1149  *
1150  * Local Variables:
1151  * eval: (c-set-style "gnu")
1152  * End:
1153  */