Common form of fib-path reproting in dumps
[vpp.git] / src / vnet / bier / bier_api.c
1 /*
2  *------------------------------------------------------------------
3  * bier_api.c - vnet BIER api
4  *
5  * Copyright (c) 2016 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <vnet/vnet.h>
21 #include <vlibmemory/api.h>
22
23 #include <vnet/api_errno.h>
24 #include <vnet/bier/bier_table.h>
25 #include <vnet/bier/bier_imp.h>
26 #include <vnet/bier/bier_disp_table.h>
27 #include <vnet/bier/bier_disp_entry.h>
28 #include <vnet/bier/bier_bit_string.h>
29 #include <vnet/bier/bier_hdr_inlines.h>
30 #include <vnet/fib/fib_path_list.h>
31 #include <vnet/fib/fib_api.h>
32 #include <vnet/fib/fib_table.h>
33 #include <vnet/mfib/mfib_table.h>
34
35 #include <vnet/vnet_msg_enum.h>
36
37 #define vl_typedefs             /* define message structures */
38 #include <vnet/vnet_all_api_h.h>
39 #undef vl_typedefs
40
41 #define vl_endianfun            /* define message structures */
42 #include <vnet/vnet_all_api_h.h>
43 #undef vl_endianfun
44
45 /* instantiate all the print functions we know about */
46 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
47 #define vl_printfun
48 #include <vnet/vnet_all_api_h.h>
49 #undef vl_printfun
50
51 #include <vlibapi/api_helper_macros.h>
52
53 #define foreach_bier_api_msg                            \
54     _(BIER_TABLE_ADD_DEL, bier_table_add_del)           \
55     _(BIER_TABLE_DUMP, bier_table_dump)                 \
56     _(BIER_ROUTE_ADD_DEL, bier_route_add_del)           \
57     _(BIER_ROUTE_DUMP, bier_route_dump)                 \
58     _(BIER_IMP_ADD, bier_imp_add)                       \
59     _(BIER_IMP_DEL, bier_imp_del)                       \
60     _(BIER_IMP_DUMP, bier_imp_dump)                     \
61     _(BIER_DISP_TABLE_ADD_DEL, bier_disp_table_add_del) \
62     _(BIER_DISP_TABLE_DUMP, bier_disp_table_dump)       \
63     _(BIER_DISP_ENTRY_ADD_DEL, bier_disp_entry_add_del) \
64     _(BIER_DISP_ENTRY_DUMP, bier_disp_entry_dump)
65
66 static void
67 vl_api_bier_table_add_del_t_handler (vl_api_bier_table_add_del_t * mp)
68 {
69     vl_api_bier_table_add_del_reply_t *rmp;
70     vnet_main_t *vnm;
71     int rv;
72
73     vnm = vnet_get_main ();
74     vnm->api_errno = 0;
75
76     if (mp->bt_tbl_id.bt_hdr_len_id >= BIER_HDR_LEN_2048)
77     {
78         rv = VNET_API_ERROR_BIER_BSL_UNSUP;
79     }
80     else
81     {
82         bier_table_id_t bti = {
83             .bti_set = mp->bt_tbl_id.bt_set,
84             .bti_sub_domain = mp->bt_tbl_id.bt_sub_domain,
85             .bti_hdr_len = mp->bt_tbl_id.bt_hdr_len_id,
86             .bti_type = BIER_TABLE_MPLS_SPF,
87             .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
88         };
89
90         if (mp->bt_is_add)
91         {
92             mpls_label_t label = ntohl(mp->bt_label);
93
94             /*
95              * convert acceptable 'don't want a label' values from 
96              * the API to the correct internal INVLID value
97              */
98             if ((0 == label) || (~0 == label))
99             {
100                 label = MPLS_LABEL_INVALID;
101             }
102             bier_table_add_or_lock(&bti, label);
103         }
104         else
105         {
106             bier_table_unlock(&bti);
107         }
108
109         rv = vnm->api_errno;
110     }
111
112     REPLY_MACRO (VL_API_BIER_TABLE_ADD_DEL_REPLY);
113 }
114
115 static void
116 send_bier_table_details (vl_api_registration_t * reg,
117                          u32 context,
118                          const bier_table_t *bt)
119 {
120     vl_api_bier_table_details_t *mp;
121
122     mp = vl_msg_api_alloc(sizeof(*mp));
123     if (!mp)
124         return;
125     memset(mp, 0, sizeof(*mp));
126     mp->_vl_msg_id = ntohs(VL_API_BIER_TABLE_DETAILS);
127     mp->context = context;
128
129     mp->bt_label = bt->bt_ll;
130     mp->bt_tbl_id.bt_set = bt->bt_id.bti_set;
131     mp->bt_tbl_id.bt_sub_domain = bt->bt_id.bti_sub_domain;
132     mp->bt_tbl_id.bt_hdr_len_id = bt->bt_id.bti_hdr_len;
133
134     vl_api_send_msg (reg, (u8 *) mp);
135 }
136
137 static void
138 vl_api_bier_table_dump_t_handler (vl_api_bier_table_dump_t * mp)
139 {
140     vl_api_registration_t *reg;
141     bier_table_t *bt;
142
143     reg = vl_api_client_index_to_registration (mp->client_index);
144     if (!reg)
145       return;
146
147     pool_foreach(bt, bier_table_pool,
148     ({
149         /*
150          * skip the ecmp tables.
151          */
152         if (bier_table_is_main(bt))
153         {
154             send_bier_table_details(reg, mp->context, bt);
155         }
156     }));
157 }
158
159 static void
160 vl_api_bier_route_add_del_t_handler (vl_api_bier_route_add_del_t * mp)
161 {
162     vl_api_bier_route_add_del_reply_t *rmp;
163     fib_route_path_t *brpaths, *brpath;
164     vnet_main_t *vnm;
165     bier_bp_t bp;
166     int rv = 0;
167     u8 ii, jj;
168
169     vnm = vnet_get_main ();
170     vnm->api_errno = 0;
171     bp = ntohl(mp->br_bp);
172     brpaths = NULL;
173
174     if (mp->br_tbl_id.bt_hdr_len_id >= BIER_HDR_LEN_2048)
175     {
176         rv = VNET_API_ERROR_BIER_BSL_UNSUP;
177         goto done;
178     }
179     if (0 == bp || bp > BIER_BP_MAX)
180     {
181         rv = -1;
182         goto done;
183     }
184
185     bier_table_id_t bti = {
186         .bti_set = mp->br_tbl_id.bt_set,
187         .bti_sub_domain = mp->br_tbl_id.bt_sub_domain,
188         .bti_hdr_len = mp->br_tbl_id.bt_hdr_len_id,
189         .bti_type = BIER_TABLE_MPLS_SPF,
190         .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
191     };
192
193     vec_validate(brpaths, mp->br_n_paths - 1);
194
195     vec_foreach_index(ii, brpaths)
196     {
197         brpath = &brpaths[ii];
198         memset(brpath, 0, sizeof(*brpath));
199         brpath->frp_sw_if_index = ~0;
200
201         vec_validate(brpath->frp_label_stack,
202                      mp->br_paths[ii].n_labels - 1);
203         for (jj = 0; jj < mp->br_paths[ii].n_labels; jj++)
204         {
205             brpath->frp_label_stack[jj].fml_value =
206                 ntohl(mp->br_paths[ii].label_stack[jj].label);
207             brpath->frp_label_stack[jj].fml_ttl =
208                 mp->br_paths[ii].label_stack[jj].ttl;
209             brpath->frp_label_stack[jj].fml_exp =
210                 mp->br_paths[ii].label_stack[jj].exp;
211             brpath->frp_label_stack[jj].fml_mode =
212                 (mp->br_paths[ii].label_stack[jj].is_uniform ?
213                  FIB_MPLS_LSP_MODE_UNIFORM :
214                  FIB_MPLS_LSP_MODE_PIPE);
215         }
216
217         if (mp->br_paths[ii].is_udp_encap)
218         {
219             brpath->frp_flags |= FIB_ROUTE_PATH_UDP_ENCAP;
220             brpath->frp_udp_encap_id = ntohl(mp->br_paths[ii].next_hop_id);
221         }
222         else
223         {
224             if (0 == mp->br_paths[ii].afi)
225             {
226                 clib_memcpy (&brpath->frp_addr.ip4,
227                              mp->br_paths[ii].next_hop,
228                              sizeof (brpath->frp_addr.ip4));
229             }
230             else
231             {
232                 clib_memcpy (&brpath->frp_addr.ip6,
233                              mp->br_paths[ii].next_hop,
234                              sizeof (brpath->frp_addr.ip6));
235             }
236             if (ip46_address_is_zero(&brpath->frp_addr))
237             {
238                 index_t bdti;
239
240                 bdti = bier_disp_table_find(ntohl(mp->br_paths[ii].table_id));
241
242                 if (INDEX_INVALID != bdti)
243                 {
244                     brpath->frp_fib_index = bdti;
245                     brpath->frp_proto = DPO_PROTO_BIER;
246                 }
247                 else
248                 {
249                     rv = VNET_API_ERROR_NO_SUCH_FIB;
250                     goto done;
251                 }
252             }
253         }
254     }
255
256     if (mp->br_is_add)
257     {
258         bier_table_route_add(&bti, bp, brpaths);
259     }
260     else
261     {
262         bier_table_route_remove(&bti, bp, brpaths);
263     }
264     vec_free(brpaths);
265
266 done:
267     rv = (rv == 0) ? vnm->api_errno : rv;
268
269     REPLY_MACRO (VL_API_BIER_ROUTE_ADD_DEL_REPLY);
270 }
271
272 typedef struct bier_route_details_walk_t_
273 {
274     vl_api_registration_t * reg;
275     u32 context;
276 } bier_route_details_walk_t;
277
278 static void
279 send_bier_route_details (const bier_table_t *bt,
280                          const bier_entry_t *be,
281                          void *args)
282 {
283     fib_route_path_encode_t *api_rpaths = NULL, *api_rpath;
284     bier_route_details_walk_t *ctx = args;
285     vl_api_bier_route_details_t *mp;
286     vl_api_fib_path_t *fp;
287     u32 n_paths, m_size;
288
289     n_paths = fib_path_list_get_n_paths(be->be_path_list);
290     m_size = sizeof(*mp) + (n_paths * sizeof(vl_api_fib_path_t));
291     mp = vl_msg_api_alloc(m_size);
292     if (!mp)
293         return;
294
295     memset(mp, 0, m_size);
296     mp->_vl_msg_id = ntohs(VL_API_BIER_ROUTE_DETAILS);
297     mp->context = ctx->context;
298
299     mp->br_tbl_id.bt_set = bt->bt_id.bti_set;
300     mp->br_tbl_id.bt_sub_domain = bt->bt_id.bti_sub_domain;
301     mp->br_tbl_id.bt_hdr_len_id = bt->bt_id.bti_hdr_len;
302     mp->br_bp = htons(be->be_bp);
303     mp->br_n_paths = htonl(n_paths);
304
305     fib_path_list_walk(be->be_path_list, fib_path_encode, &api_rpaths);
306
307     fp = mp->br_paths;
308     vec_foreach (api_rpath, api_rpaths)
309     {
310         fib_api_path_encode(api_rpath, fp);
311         fp++;
312     }
313
314     vl_api_send_msg (ctx->reg, (u8 *) mp);
315 }
316
317 static void
318 vl_api_bier_route_dump_t_handler (vl_api_bier_route_dump_t * mp)
319 {
320     vl_api_registration_t *reg;
321
322     reg = vl_api_client_index_to_registration (mp->client_index);
323     if (!reg)
324       return;
325
326     bier_table_id_t bti = {
327         .bti_set = mp->br_tbl_id.bt_set,
328         .bti_sub_domain = mp->br_tbl_id.bt_sub_domain,
329         .bti_hdr_len = mp->br_tbl_id.bt_hdr_len_id,
330         .bti_type = BIER_TABLE_MPLS_SPF,
331         .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
332     };
333     bier_route_details_walk_t ctx = {
334         .reg = reg,
335         .context = mp->context,
336     };
337     bier_table_walk(&bti, send_bier_route_details, &ctx);
338 }
339
340 static void
341 vl_api_bier_imp_add_t_handler (vl_api_bier_imp_add_t * mp)
342 {
343     vl_api_bier_imp_add_reply_t *rmp;
344     vnet_main_t *vnm;
345     index_t bii;
346     int rv = 0;
347
348     vnm = vnet_get_main ();
349     vnm->api_errno = 0;
350
351     /*
352      * The BSL support by VPP is limited to the size of the
353      * available space in the vlib_buffer_t
354      */
355     if (mp->bi_tbl_id.bt_hdr_len_id >= BIER_HDR_LEN_2048)
356     {
357         rv = VNET_API_ERROR_BIER_BSL_UNSUP;
358     }
359     else
360     {
361         bier_table_id_t bti = {
362             .bti_set = mp->bi_tbl_id.bt_set,
363             .bti_sub_domain = mp->bi_tbl_id.bt_sub_domain,
364             .bti_hdr_len = mp->bi_tbl_id.bt_hdr_len_id,
365             .bti_type = BIER_TABLE_MPLS_SPF,
366             .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
367         };
368         bier_bit_string_t bs = {
369             .bbs_len = mp->bi_n_bytes,
370             .bbs_buckets = mp->bi_bytes,
371         };
372
373         bii = bier_imp_add_or_lock(&bti, ntohs(mp->bi_src), &bs);
374     }
375
376     REPLY_MACRO2 (VL_API_BIER_IMP_ADD_REPLY,
377     ({
378         rmp->bi_index = ntohl (bii);
379     }));
380 }
381
382 static void
383 vl_api_bier_imp_del_t_handler (vl_api_bier_imp_del_t * mp)
384 {
385     vl_api_bier_imp_del_reply_t *rmp;
386     vnet_main_t *vnm;
387     int rv = 0;
388
389     vnm = vnet_get_main ();
390     vnm->api_errno = 0;
391
392     bier_imp_unlock(ntohl(mp->bi_index));
393
394     REPLY_MACRO(VL_API_BIER_IMP_DEL_REPLY);
395 }
396
397 static void
398 send_bier_imp_details (vl_api_registration_t * reg,
399                        u32 context,
400                        const bier_imp_t *bi)
401 {
402     vl_api_bier_imp_details_t *mp;
403     bier_hdr_t copy;
404     u8 n_bytes;
405
406     copy = bi->bi_hdr;
407     bier_hdr_ntoh(&copy);
408
409     n_bytes = bier_hdr_len_id_to_num_bytes(
410                   bier_hdr_get_len_id(&copy));
411     mp = vl_msg_api_alloc(sizeof(*mp) + n_bytes);
412     if (!mp)
413         return;
414     memset(mp, 0, sizeof(*mp)+n_bytes);
415     mp->_vl_msg_id = ntohs(VL_API_BIER_IMP_DETAILS);
416     mp->context = context;
417
418     mp->bi_tbl_id.bt_set = bi->bi_tbl.bti_set;
419     mp->bi_tbl_id.bt_sub_domain = bi->bi_tbl.bti_sub_domain;
420     mp->bi_tbl_id.bt_hdr_len_id = bi->bi_tbl.bti_hdr_len;
421
422     mp->bi_src = htons(bier_hdr_get_src_id(&copy));
423     mp->bi_n_bytes = n_bytes;
424     memcpy(mp->bi_bytes, bi->bi_bits, n_bytes);
425
426     vl_api_send_msg (reg, (u8 *) mp);
427 }
428
429 static void
430 vl_api_bier_imp_dump_t_handler (vl_api_bier_imp_dump_t * mp)
431 {
432     vl_api_registration_t *reg;
433     bier_imp_t *bi;
434
435     reg = vl_api_client_index_to_registration (mp->client_index);
436     if (!reg)
437       return;
438
439     pool_foreach(bi, bier_imp_pool,
440     ({
441         send_bier_imp_details(reg, mp->context, bi);
442     }));
443 }
444
445 static void
446 vl_api_bier_disp_table_add_del_t_handler (vl_api_bier_disp_table_add_del_t * mp)
447 {
448     vl_api_bier_disp_table_add_del_reply_t *rmp;
449     vnet_main_t *vnm;
450     u32 table_id;
451     int rv;
452
453     vnm = vnet_get_main ();
454     vnm->api_errno = 0;
455     table_id = ntohl(mp->bdt_tbl_id);
456
457     if (mp->bdt_is_add)
458     {
459         bier_disp_table_add_or_lock(table_id);
460     }
461     else
462     {
463         bier_disp_table_unlock_w_table_id(table_id);
464     }
465
466     rv = vnm->api_errno;
467
468     REPLY_MACRO (VL_API_BIER_DISP_TABLE_ADD_DEL_REPLY);
469 }
470
471 static void
472 send_bier_disp_table_details (vl_api_registration_t * reg,
473                               u32 context,
474                               const bier_disp_table_t *bdt)
475 {
476     vl_api_bier_disp_table_details_t *mp;
477
478     mp = vl_msg_api_alloc(sizeof(*mp));
479     if (!mp)
480         return;
481     memset(mp, 0, sizeof(*mp));
482     mp->_vl_msg_id = ntohs(VL_API_BIER_DISP_TABLE_DETAILS);
483     mp->context = context;
484
485     mp->bdt_tbl_id = htonl(bdt->bdt_table_id);
486
487     vl_api_send_msg (reg, (u8 *) mp);
488 }
489
490 static void
491 vl_api_bier_disp_table_dump_t_handler (vl_api_bier_disp_table_dump_t * mp)
492 {
493     vl_api_registration_t *reg;
494     bier_disp_table_t *bdt;
495
496     reg = vl_api_client_index_to_registration (mp->client_index);
497     if (!reg)
498       return;
499
500     pool_foreach(bdt, bier_disp_table_pool,
501     ({
502         send_bier_disp_table_details(reg, mp->context, bdt);
503     }));
504 }
505
506 static void
507 vl_api_bier_disp_entry_add_del_t_handler (vl_api_bier_disp_entry_add_del_t * mp)
508 {
509     vl_api_bier_disp_entry_add_del_reply_t *rmp;
510     fib_route_path_t *brps = NULL, *brp;
511     vnet_main_t *vnm;
512     bier_bp_t bp;
513     u32 table_id;
514     int rv = 0;
515     u32 ii;
516
517     vnm = vnet_get_main ();
518     vnm->api_errno = 0;
519     table_id = ntohl(mp->bde_tbl_id);
520     bp = ntohs(mp->bde_bp);
521
522     /*
523      * BP=0 is the default route
524      */
525     if (bp > 0xffff)
526     {
527         rv = -1;
528         goto done;
529     }
530
531     vec_validate(brps, mp->bde_n_paths - 1);
532     vec_foreach_index(ii, brps)
533     {
534         brp = &brps[ii];
535         brp->frp_fib_index = ntohl(mp->bde_paths[ii].table_id);
536         brp->frp_sw_if_index = ntohl(mp->bde_paths[ii].sw_if_index);
537
538         if (~0 != ntohl(mp->bde_paths[ii].rpf_id))
539         {
540             brp->frp_flags = FIB_ROUTE_PATH_RPF_ID;
541             brp->frp_rpf_id = ntohl(mp->bde_paths[ii].rpf_id);
542         }
543
544         if (0 == mp->bde_paths[ii].afi)
545         {
546             clib_memcpy (&brp->frp_addr.ip4,
547                          mp->bde_paths[ii].next_hop,
548                          sizeof (brp->frp_addr.ip4));
549         }
550         else
551         {
552             clib_memcpy (&brp->frp_addr.ip6,
553                          mp->bde_paths[ii].next_hop,
554                          sizeof (brp->frp_addr.ip6));
555         }
556         if (ip46_address_is_zero(&brp->frp_addr))
557         {
558             index_t fti;
559
560             switch (mp->bde_payload_proto)
561             {
562             case BIER_HDR_PROTO_INVALID:
563             case BIER_HDR_PROTO_MPLS_DOWN_STREAM:
564             case BIER_HDR_PROTO_MPLS_UP_STREAM:
565             case BIER_HDR_PROTO_ETHERNET:
566             case BIER_HDR_PROTO_VXLAN:
567             case BIER_HDR_PROTO_CTRL:
568             case BIER_HDR_PROTO_OAM:
569                 rv = VNET_API_ERROR_UNSUPPORTED;
570                 goto done;
571                 break;
572             case BIER_HDR_PROTO_IPV4:
573             case BIER_HDR_PROTO_IPV6:
574             {
575                 fib_protocol_t fproto;
576
577                 fproto = (mp->bde_payload_proto == BIER_HDR_PROTO_IPV4 ?
578                           FIB_PROTOCOL_IP4 :
579                           FIB_PROTOCOL_IP6);
580
581                 if (brp->frp_flags & FIB_ROUTE_PATH_RPF_ID)
582                 {
583                     fti = mfib_table_find (fproto,
584                                            ntohl (mp->bde_paths[ii].table_id));
585                 }
586                 else
587                 {
588                     fti = fib_table_find (fproto,
589                                           ntohl (mp->bde_paths[ii].table_id));
590                 }
591
592                 if (INDEX_INVALID != fti)
593                 {
594                     brp->frp_fib_index = fti;
595                 }
596                 else
597                 {
598                     rv = VNET_API_ERROR_NO_SUCH_FIB;
599                     goto done;
600                 }
601                 break;
602             }
603             }
604         }
605     }
606
607     if (mp->bde_is_add)
608     {
609         bier_disp_table_entry_path_add(table_id, bp,
610                                        mp->bde_payload_proto,
611                                        brps);
612     }
613     else
614     {
615         bier_disp_table_entry_path_remove(table_id, bp,
616                                           mp->bde_payload_proto,
617                                           brps);
618     }
619
620 done:
621     vec_free(brps);
622     rv = (rv == 0) ? vnm->api_errno : rv;
623
624     REPLY_MACRO (VL_API_BIER_DISP_ENTRY_ADD_DEL_REPLY);
625 }
626
627 typedef struct bier_disp_entry_details_walk_t_
628 {
629     vl_api_registration_t * reg;
630     u32 context;
631 } bier_disp_entry_details_walk_t;
632
633 static void
634 send_bier_disp_entry_details (const bier_disp_table_t *bdt,
635                               const bier_disp_entry_t *bde,
636                               u16 bp,
637                               void *args)
638 {
639     fib_route_path_encode_t *api_rpaths = NULL, *api_rpath;
640     bier_disp_entry_details_walk_t *ctx = args;
641     vl_api_bier_disp_entry_details_t *mp;
642     bier_hdr_proto_id_t pproto;
643     vl_api_fib_path_t *fp;
644     u32 n_paths, m_size;
645
646     FOR_EACH_BIER_HDR_PROTO(pproto)
647     {
648         fib_node_index_t pl = bde->bde_pl[pproto];
649         if (INDEX_INVALID != pl)
650         {
651             n_paths = fib_path_list_get_n_paths(pl);
652             m_size = sizeof(*mp) + (n_paths * sizeof(vl_api_fib_path_t));
653             mp = vl_msg_api_alloc(m_size);
654             if (!mp)
655                 return;
656
657             memset(mp, 0, m_size);
658             mp->_vl_msg_id = ntohs(VL_API_BIER_DISP_ENTRY_DETAILS);
659             mp->context = ctx->context;
660
661             mp->bde_tbl_id = htonl(bdt->bdt_table_id);
662             mp->bde_n_paths = htonl(n_paths);
663             mp->bde_payload_proto = pproto;
664             mp->bde_bp = htons(bp);
665
666             fib_path_list_walk(pl, fib_path_encode, &api_rpaths);
667
668             fp = mp->bde_paths;
669             vec_foreach (api_rpath, api_rpaths)
670             {
671                 fib_api_path_encode(api_rpath, fp);
672                 fp++;
673             }
674
675             vl_api_send_msg (ctx->reg, (u8 *) mp);
676         }
677     }
678 }
679
680 static void
681 vl_api_bier_disp_entry_dump_t_handler (vl_api_bier_disp_entry_dump_t * mp)
682 {
683     vl_api_registration_t *reg;
684
685     reg = vl_api_client_index_to_registration (mp->client_index);
686     if (!reg)
687       return;
688
689     bier_disp_entry_details_walk_t ctx = {
690         .reg = reg,
691         .context = mp->context,
692     };
693     bier_disp_table_walk(ntohl(mp->bde_tbl_id),
694                          send_bier_disp_entry_details,
695                          &ctx);
696 }
697
698 #define vl_msg_name_crc_list
699 #include <vnet/bier/bier.api.h>
700 #undef vl_msg_name_crc_list
701
702 static void
703 setup_message_id_table (api_main_t * am)
704 {
705 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
706     foreach_vl_msg_name_crc_bier;
707 #undef _
708 }
709
710 static clib_error_t *
711 bier_api_hookup (vlib_main_t * vm)
712 {
713     api_main_t *am = &api_main;
714
715 #define _(N,n)                                          \
716     vl_msg_api_set_handlers(VL_API_##N, #n,             \
717                             vl_api_##n##_t_handler,     \
718                             vl_noop_handler,            \
719                             vl_api_##n##_t_endian,      \
720                             vl_api_##n##_t_print,       \
721                             sizeof(vl_api_##n##_t), 1);
722     foreach_bier_api_msg;
723 #undef _
724
725     /*
726      * Set up the (msg_name, crc, message-id) table
727      */
728     setup_message_id_table (am);
729
730     return 0;
731 }
732
733 VLIB_API_INIT_FUNCTION (bier_api_hookup);