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