vlib: fix use of RTLD_DEEPBIND for musl
[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/format_fns.h>
36 #include <bier/bier.api_enum.h>
37 #include <bier/bier.api_types.h>
38
39 #define REPLY_MSG_ID_BASE bier_main.msg_id_base
40 #include <vlibapi/api_helper_macros.h>
41
42 typedef struct
43 {
44   u16 msg_id_base;
45 } bier_main_t;
46
47 bier_main_t bier_main;
48
49 static void
50 vl_api_bier_table_add_del_t_handler (vl_api_bier_table_add_del_t * mp)
51 {
52     vl_api_bier_table_add_del_reply_t *rmp;
53     vnet_main_t *vnm;
54     int rv;
55
56     vnm = vnet_get_main ();
57     vnm->api_errno = 0;
58
59     if (mp->bt_tbl_id.bt_hdr_len_id >= BIER_HDR_LEN_2048)
60     {
61         rv = VNET_API_ERROR_BIER_BSL_UNSUP;
62     }
63     else
64     {
65         bier_table_id_t bti = {
66             .bti_set = mp->bt_tbl_id.bt_set,
67             .bti_sub_domain = mp->bt_tbl_id.bt_sub_domain,
68             .bti_hdr_len = mp->bt_tbl_id.bt_hdr_len_id,
69             .bti_type = BIER_TABLE_MPLS_SPF,
70             .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
71         };
72
73         if (mp->bt_is_add)
74         {
75             mpls_label_t label = ntohl(mp->bt_label);
76
77             /*
78              * convert acceptable 'don't want a label' values from 
79              * the API to the correct internal INVLID value
80              */
81             if ((0 == label) || (~0 == label))
82             {
83                 label = MPLS_LABEL_INVALID;
84             }
85             bier_table_add_or_lock(&bti, label);
86         }
87         else
88         {
89             bier_table_unlock(&bti);
90         }
91
92         rv = vnm->api_errno;
93     }
94
95     REPLY_MACRO (VL_API_BIER_TABLE_ADD_DEL_REPLY);
96 }
97
98 static void
99 send_bier_table_details (vl_api_registration_t * reg,
100                          u32 context,
101                          const bier_table_t *bt)
102 {
103     vl_api_bier_table_details_t *mp;
104
105     mp = vl_msg_api_alloc(sizeof(*mp));
106     if (!mp)
107         return;
108     clib_memset(mp, 0, sizeof(*mp));
109     mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_BIER_TABLE_DETAILS);
110     mp->context = context;
111
112     mp->bt_label = bt->bt_ll;
113     mp->bt_tbl_id.bt_set = bt->bt_id.bti_set;
114     mp->bt_tbl_id.bt_sub_domain = bt->bt_id.bti_sub_domain;
115     mp->bt_tbl_id.bt_hdr_len_id = bt->bt_id.bti_hdr_len;
116
117     vl_api_send_msg (reg, (u8 *) mp);
118 }
119
120 static void
121 vl_api_bier_table_dump_t_handler (vl_api_bier_table_dump_t * mp)
122 {
123     vl_api_registration_t *reg;
124     bier_table_t *bt;
125
126     reg = vl_api_client_index_to_registration (mp->client_index);
127     if (!reg)
128       return;
129
130     pool_foreach (bt, bier_table_pool)
131      {
132         /*
133          * skip the ecmp tables.
134          */
135         if (bier_table_is_main(bt))
136         {
137             send_bier_table_details(reg, mp->context, bt);
138         }
139     }
140 }
141
142 static void
143 vl_api_bier_route_add_del_t_handler (vl_api_bier_route_add_del_t * mp)
144 {
145     vl_api_bier_route_add_del_reply_t *rmp;
146     fib_route_path_t *brpaths, *brpath;
147     vnet_main_t *vnm;
148     bier_bp_t bp;
149     int rv = 0;
150     u8 ii;
151
152     vnm = vnet_get_main ();
153     vnm->api_errno = 0;
154     bp = ntohl(mp->br_route.br_bp);
155     brpaths = NULL;
156
157     if (mp->br_route.br_tbl_id.bt_hdr_len_id >= BIER_HDR_LEN_2048)
158     {
159         rv = VNET_API_ERROR_BIER_BSL_UNSUP;
160         goto done;
161     }
162     if (0 == bp || bp > BIER_BP_MAX)
163     {
164         rv = -1;
165         goto done;
166     }
167
168     bier_table_id_t bti = {
169         .bti_set = mp->br_route.br_tbl_id.bt_set,
170         .bti_sub_domain = mp->br_route.br_tbl_id.bt_sub_domain,
171         .bti_hdr_len = mp->br_route.br_tbl_id.bt_hdr_len_id,
172         .bti_type = BIER_TABLE_MPLS_SPF,
173         .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
174     };
175
176     vec_validate(brpaths, mp->br_route.br_n_paths - 1);
177
178     vec_foreach_index(ii, brpaths)
179     {
180         brpath = &brpaths[ii];
181         rv = fib_api_path_decode(&mp->br_route.br_paths[ii], brpath);
182
183         if (0 != rv)
184         {
185             goto done;
186         }
187     }
188
189     if (mp->br_is_replace)
190     {
191         if (0 == vec_len(brpaths))
192         {
193             bier_table_route_delete(&bti, bp);
194         }
195         else
196         {
197             bier_table_route_path_update(&bti, bp, brpaths);
198         }
199     }
200     else if (mp->br_is_add)
201     {
202         bier_table_route_path_add(&bti, bp, brpaths);
203     }
204     else
205     {
206         bier_table_route_path_remove(&bti, bp, brpaths);
207     }
208     vec_free(brpaths);
209
210 done:
211     rv = (rv == 0) ? vnm->api_errno : rv;
212
213     REPLY_MACRO (VL_API_BIER_ROUTE_ADD_DEL_REPLY);
214 }
215
216 typedef struct bier_route_details_walk_t_
217 {
218     vl_api_registration_t * reg;
219     u32 context;
220 } bier_route_details_walk_t;
221
222 static void
223 send_bier_route_details (const bier_table_t *bt,
224                          const bier_entry_t *be,
225                          void *args)
226 {
227     bier_route_details_walk_t *ctx = args;
228     vl_api_bier_route_details_t *mp;
229     fib_path_encode_ctx_t path_ctx = {
230         .rpaths = NULL,
231     };
232     fib_route_path_t *rpath;
233     vl_api_fib_path_t *fp;
234     u32 n_paths, m_size;
235
236     n_paths = fib_path_list_get_n_paths(be->be_path_list);
237     m_size = sizeof(*mp) + (n_paths * sizeof(vl_api_fib_path_t));
238     mp = vl_msg_api_alloc(m_size);
239     if (!mp)
240         return;
241
242     clib_memset(mp, 0, m_size);
243     mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_BIER_ROUTE_DETAILS);
244     mp->context = ctx->context;
245
246     mp->br_route.br_tbl_id.bt_set = bt->bt_id.bti_set;
247     mp->br_route.br_tbl_id.bt_sub_domain = bt->bt_id.bti_sub_domain;
248     mp->br_route.br_tbl_id.bt_hdr_len_id = bt->bt_id.bti_hdr_len;
249     mp->br_route.br_bp = htonl(be->be_bp);
250     mp->br_route.br_n_paths = htonl(n_paths);
251
252     fib_path_list_walk_w_ext(be->be_path_list,
253                              NULL,
254                              fib_path_encode,
255                             &path_ctx);
256
257     fp = mp->br_route.br_paths;
258     vec_foreach (rpath, path_ctx.rpaths)
259     {
260         fib_api_path_encode(rpath, fp);
261         fp++;
262     }
263
264     vec_free(path_ctx.rpaths);
265     vl_api_send_msg (ctx->reg, (u8 *) mp);
266 }
267
268 static void
269 vl_api_bier_route_dump_t_handler (vl_api_bier_route_dump_t * mp)
270 {
271     vl_api_registration_t *reg;
272
273     reg = vl_api_client_index_to_registration (mp->client_index);
274     if (!reg)
275       return;
276
277     bier_table_id_t bti = {
278         .bti_set = mp->br_tbl_id.bt_set,
279         .bti_sub_domain = mp->br_tbl_id.bt_sub_domain,
280         .bti_hdr_len = mp->br_tbl_id.bt_hdr_len_id,
281         .bti_type = BIER_TABLE_MPLS_SPF,
282         .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
283     };
284     bier_route_details_walk_t ctx = {
285         .reg = reg,
286         .context = mp->context,
287     };
288     bier_table_walk(&bti, send_bier_route_details, &ctx);
289 }
290
291 static void
292 vl_api_bier_imp_add_t_handler (vl_api_bier_imp_add_t * mp)
293 {
294     vl_api_bier_imp_add_reply_t *rmp;
295     vnet_main_t *vnm;
296     index_t bii = ~0;
297     int rv = 0;
298
299     vnm = vnet_get_main ();
300     vnm->api_errno = 0;
301
302     /*
303      * The BSL support by VPP is limited to the size of the
304      * available space in the vlib_buffer_t
305      */
306     if (mp->bi_tbl_id.bt_hdr_len_id >= BIER_HDR_LEN_2048)
307     {
308         rv = VNET_API_ERROR_BIER_BSL_UNSUP;
309     }
310     else
311     {
312         bier_table_id_t bti = {
313             .bti_set = mp->bi_tbl_id.bt_set,
314             .bti_sub_domain = mp->bi_tbl_id.bt_sub_domain,
315             .bti_hdr_len = mp->bi_tbl_id.bt_hdr_len_id,
316             .bti_type = BIER_TABLE_MPLS_SPF,
317             .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
318         };
319         bier_bit_string_t bs = {
320             .bbs_len = mp->bi_n_bytes,
321             .bbs_buckets = mp->bi_bytes,
322         };
323
324         bii = bier_imp_add_or_lock(&bti, ntohs(mp->bi_src), &bs);
325     }
326
327     REPLY_MACRO2 (VL_API_BIER_IMP_ADD_REPLY,
328     ({
329         rmp->bi_index = ntohl (bii);
330     }));
331 }
332
333 static void
334 vl_api_bier_imp_del_t_handler (vl_api_bier_imp_del_t * mp)
335 {
336     vl_api_bier_imp_del_reply_t *rmp;
337     vnet_main_t *vnm;
338     int rv = 0;
339
340     vnm = vnet_get_main ();
341     vnm->api_errno = 0;
342
343     bier_imp_unlock(ntohl(mp->bi_index));
344
345     REPLY_MACRO(VL_API_BIER_IMP_DEL_REPLY);
346 }
347
348 static void
349 send_bier_imp_details (vl_api_registration_t * reg,
350                        u32 context,
351                        const bier_imp_t *bi)
352 {
353     vl_api_bier_imp_details_t *mp;
354     bier_hdr_t copy;
355     u8 n_bytes;
356
357     copy = bi->bi_hdr;
358     bier_hdr_ntoh(&copy);
359
360     n_bytes = bier_hdr_len_id_to_num_bytes(
361                   bier_hdr_get_len_id(&copy));
362     mp = vl_msg_api_alloc(sizeof(*mp) + n_bytes);
363     if (!mp)
364         return;
365     clib_memset(mp, 0, sizeof(*mp)+n_bytes);
366     mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_BIER_IMP_DETAILS);
367     mp->context = context;
368
369     mp->bi_tbl_id.bt_set = bi->bi_tbl.bti_set;
370     mp->bi_tbl_id.bt_sub_domain = bi->bi_tbl.bti_sub_domain;
371     mp->bi_tbl_id.bt_hdr_len_id = bi->bi_tbl.bti_hdr_len;
372
373     mp->bi_src = htons(bier_hdr_get_src_id(&copy));
374     mp->bi_n_bytes = n_bytes;
375     memcpy(mp->bi_bytes, bi->bi_bits, n_bytes);
376
377     vl_api_send_msg (reg, (u8 *) mp);
378 }
379
380 static void
381 vl_api_bier_imp_dump_t_handler (vl_api_bier_imp_dump_t * mp)
382 {
383     vl_api_registration_t *reg;
384     bier_imp_t *bi;
385
386     reg = vl_api_client_index_to_registration (mp->client_index);
387     if (!reg)
388       return;
389
390     pool_foreach (bi, bier_imp_pool)
391      {
392         send_bier_imp_details(reg, mp->context, bi);
393     }
394 }
395
396 static void
397 vl_api_bier_disp_table_add_del_t_handler (vl_api_bier_disp_table_add_del_t * mp)
398 {
399     vl_api_bier_disp_table_add_del_reply_t *rmp;
400     vnet_main_t *vnm;
401     u32 table_id;
402     int rv;
403
404     vnm = vnet_get_main ();
405     vnm->api_errno = 0;
406     table_id = ntohl(mp->bdt_tbl_id);
407
408     if (mp->bdt_is_add)
409     {
410         bier_disp_table_add_or_lock(table_id);
411     }
412     else
413     {
414         bier_disp_table_unlock_w_table_id(table_id);
415     }
416
417     rv = vnm->api_errno;
418
419     REPLY_MACRO (VL_API_BIER_DISP_TABLE_ADD_DEL_REPLY);
420 }
421
422 static void
423 send_bier_disp_table_details (vl_api_registration_t * reg,
424                               u32 context,
425                               const bier_disp_table_t *bdt)
426 {
427     vl_api_bier_disp_table_details_t *mp;
428
429     mp = vl_msg_api_alloc(sizeof(*mp));
430     if (!mp)
431         return;
432     clib_memset(mp, 0, sizeof(*mp));
433     mp->_vl_msg_id =
434       ntohs (REPLY_MSG_ID_BASE + VL_API_BIER_DISP_TABLE_DETAILS);
435     mp->context = context;
436
437     mp->bdt_tbl_id = htonl(bdt->bdt_table_id);
438
439     vl_api_send_msg (reg, (u8 *) mp);
440 }
441
442 static void
443 vl_api_bier_disp_table_dump_t_handler (vl_api_bier_disp_table_dump_t * mp)
444 {
445     vl_api_registration_t *reg;
446     bier_disp_table_t *bdt;
447
448     reg = vl_api_client_index_to_registration (mp->client_index);
449     if (!reg)
450       return;
451
452     pool_foreach (bdt, bier_disp_table_pool)
453      {
454         send_bier_disp_table_details(reg, mp->context, bdt);
455     }
456 }
457
458 static void
459 vl_api_bier_disp_entry_add_del_t_handler (vl_api_bier_disp_entry_add_del_t * mp)
460 {
461     vl_api_bier_disp_entry_add_del_reply_t *rmp;
462     fib_route_path_t *brps = NULL, *brp;
463     vnet_main_t *vnm;
464     bier_bp_t bp;
465     u32 table_id;
466     int rv = 0;
467     u32 ii;
468
469     vnm = vnet_get_main ();
470     vnm->api_errno = 0;
471     table_id = ntohl(mp->bde_tbl_id);
472     bp = ntohs(mp->bde_bp);
473
474     /*
475      * BP=0 is the default route
476      */
477     if (bp > 0xffff)
478     {
479         rv = -1;
480         goto done;
481     }
482
483     vec_validate(brps, mp->bde_n_paths - 1);
484     vec_foreach_index(ii, brps)
485     {
486         brp = &brps[ii];
487         brp->frp_fib_index = ntohl(mp->bde_paths[ii].table_id);
488         brp->frp_sw_if_index = ntohl(mp->bde_paths[ii].sw_if_index);
489
490         if (~0 != ntohl(mp->bde_paths[ii].rpf_id))
491         {
492             brp->frp_flags = FIB_ROUTE_PATH_RPF_ID;
493             brp->frp_rpf_id = ntohl(mp->bde_paths[ii].rpf_id);
494         }
495
496         if (FIB_API_PATH_NH_PROTO_IP4 == mp->bde_paths[ii].proto)
497         {
498             clib_memcpy (&brp->frp_addr.ip4,
499                          &mp->bde_paths[ii].nh.address.ip4,
500                          sizeof (brp->frp_addr.ip4));
501         }
502         else if (FIB_API_PATH_NH_PROTO_IP6 == mp->bde_paths[ii].proto)
503         {
504             clib_memcpy (&brp->frp_addr.ip6,
505                          &mp->bde_paths[ii].nh.address.ip6,
506                          sizeof (brp->frp_addr.ip6));
507         }
508         if (ip46_address_is_zero(&brp->frp_addr))
509         {
510             index_t fti;
511
512             switch (mp->bde_payload_proto)
513             {
514             case BIER_HDR_PROTO_INVALID:
515             case BIER_HDR_PROTO_MPLS_DOWN_STREAM:
516             case BIER_HDR_PROTO_MPLS_UP_STREAM:
517             case BIER_HDR_PROTO_ETHERNET:
518             case BIER_HDR_PROTO_VXLAN:
519             case BIER_HDR_PROTO_CTRL:
520             case BIER_HDR_PROTO_OAM:
521                 rv = VNET_API_ERROR_UNSUPPORTED;
522                 goto done;
523                 break;
524             case BIER_HDR_PROTO_IPV4:
525             case BIER_HDR_PROTO_IPV6:
526             {
527                 fib_protocol_t fproto;
528
529                 fproto = (mp->bde_payload_proto == BIER_HDR_PROTO_IPV4 ?
530                           FIB_PROTOCOL_IP4 :
531                           FIB_PROTOCOL_IP6);
532
533                 if (brp->frp_flags & FIB_ROUTE_PATH_RPF_ID)
534                 {
535                     fti = mfib_table_find (fproto,
536                                            ntohl (mp->bde_paths[ii].table_id));
537                 }
538                 else
539                 {
540                     fti = fib_table_find (fproto,
541                                           ntohl (mp->bde_paths[ii].table_id));
542                 }
543
544                 if (INDEX_INVALID != fti)
545                 {
546                     brp->frp_fib_index = fti;
547                 }
548                 else
549                 {
550                     rv = VNET_API_ERROR_NO_SUCH_FIB;
551                     goto done;
552                 }
553                 break;
554             }
555             }
556         }
557     }
558
559     if (mp->bde_is_add)
560     {
561         bier_disp_table_entry_path_add(table_id, bp,
562                                        mp->bde_payload_proto,
563                                        brps);
564     }
565     else
566     {
567         bier_disp_table_entry_path_remove(table_id, bp,
568                                           mp->bde_payload_proto,
569                                           brps);
570     }
571
572 done:
573     vec_free(brps);
574     rv = (rv == 0) ? vnm->api_errno : rv;
575
576     REPLY_MACRO (VL_API_BIER_DISP_ENTRY_ADD_DEL_REPLY);
577 }
578
579 typedef struct bier_disp_entry_details_walk_t_
580 {
581     vl_api_registration_t * reg;
582     u32 context;
583 } bier_disp_entry_details_walk_t;
584
585 static void
586 send_bier_disp_entry_details (const bier_disp_table_t *bdt,
587                               const bier_disp_entry_t *bde,
588                               u16 bp,
589                               void *args)
590 {
591     bier_disp_entry_details_walk_t *ctx = args;
592     vl_api_bier_disp_entry_details_t *mp;
593     bier_hdr_proto_id_t pproto;
594     vl_api_fib_path_t *fp;
595     u32 n_paths, m_size;
596
597     FOR_EACH_BIER_HDR_PROTO(pproto)
598     {
599         fib_node_index_t pl = bde->bde_pl[pproto];
600
601         if (INDEX_INVALID != pl)
602         {
603             fib_path_encode_ctx_t path_ctx = {
604                 .rpaths = NULL,
605             };
606             fib_route_path_t *rpath;
607
608             n_paths = fib_path_list_get_n_paths(pl);
609             m_size = sizeof(*mp) + (n_paths * sizeof(vl_api_fib_path_t));
610             mp = vl_msg_api_alloc(m_size);
611             if (!mp)
612                 return;
613
614             clib_memset(mp, 0, m_size);
615             mp->_vl_msg_id =
616               ntohs (REPLY_MSG_ID_BASE + VL_API_BIER_DISP_ENTRY_DETAILS);
617             mp->context = ctx->context;
618
619             mp->bde_tbl_id = htonl (bdt->bdt_table_id);
620             mp->bde_n_paths = htonl (n_paths);
621             mp->bde_payload_proto = pproto;
622             mp->bde_bp = htons (bp);
623
624             fib_path_list_walk_w_ext (pl, NULL, fib_path_encode, &path_ctx);
625
626             fp = mp->bde_paths;
627             vec_foreach (rpath, path_ctx.rpaths)
628               {
629                 fib_api_path_encode (rpath, fp);
630                 fp++;
631               }
632
633             vl_api_send_msg (ctx->reg, (u8 *) mp);
634             vec_free (path_ctx.rpaths);
635         }
636     }
637 }
638
639 static void
640 vl_api_bier_disp_entry_dump_t_handler (vl_api_bier_disp_entry_dump_t * mp)
641 {
642     vl_api_registration_t *reg;
643
644     reg = vl_api_client_index_to_registration (mp->client_index);
645     if (!reg)
646       return;
647
648     bier_disp_entry_details_walk_t ctx = {
649         .reg = reg,
650         .context = mp->context,
651     };
652     bier_disp_table_walk(ntohl(mp->bde_tbl_id),
653                          send_bier_disp_entry_details,
654                          &ctx);
655 }
656
657 #include <bier/bier.api.c>
658
659 static clib_error_t *
660 bier_api_hookup (vlib_main_t * vm)
661 {
662   bier_main.msg_id_base = setup_message_id_table ();
663
664   return 0;
665 }
666
667 VLIB_API_INIT_FUNCTION (bier_api_hookup);