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