BIER coveroty fix for unintialised return value on error
[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 #include <vnet/fib/fib_api.h>
53
54 #define foreach_bier_api_msg                            \
55     _(BIER_TABLE_ADD_DEL, bier_table_add_del)           \
56     _(BIER_TABLE_DUMP, bier_table_dump)                 \
57     _(BIER_ROUTE_ADD_DEL, bier_route_add_del)           \
58     _(BIER_ROUTE_DUMP, bier_route_dump)                 \
59     _(BIER_IMP_ADD, bier_imp_add)                       \
60     _(BIER_IMP_DEL, bier_imp_del)                       \
61     _(BIER_IMP_DUMP, bier_imp_dump)                     \
62     _(BIER_DISP_TABLE_ADD_DEL, bier_disp_table_add_del) \
63     _(BIER_DISP_TABLE_DUMP, bier_disp_table_dump)       \
64     _(BIER_DISP_ENTRY_ADD_DEL, bier_disp_entry_add_del) \
65     _(BIER_DISP_ENTRY_DUMP, bier_disp_entry_dump)
66
67 static void
68 vl_api_bier_table_add_del_t_handler (vl_api_bier_table_add_del_t * mp)
69 {
70     vl_api_bier_table_add_del_reply_t *rmp;
71     vnet_main_t *vnm;
72     int rv;
73
74     vnm = vnet_get_main ();
75     vnm->api_errno = 0;
76
77     if (mp->bt_tbl_id.bt_hdr_len_id >= BIER_HDR_LEN_2048)
78     {
79         rv = VNET_API_ERROR_BIER_BSL_UNSUP;
80     }
81     else
82     {
83         bier_table_id_t bti = {
84             .bti_set = mp->bt_tbl_id.bt_set,
85             .bti_sub_domain = mp->bt_tbl_id.bt_sub_domain,
86             .bti_hdr_len = mp->bt_tbl_id.bt_hdr_len_id,
87             .bti_type = BIER_TABLE_MPLS_SPF,
88             .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
89         };
90
91         if (mp->bt_is_add)
92         {
93             mpls_label_t label = ntohl(mp->bt_label);
94
95             /*
96              * convert acceptable 'don't want a label' values from 
97              * the API to the correct internal INVLID value
98              */
99             if ((0 == label) || (~0 == label))
100             {
101                 label = MPLS_LABEL_INVALID;
102             }
103             bier_table_add_or_lock(&bti, label);
104         }
105         else
106         {
107             bier_table_unlock(&bti);
108         }
109
110         rv = vnm->api_errno;
111     }
112
113     REPLY_MACRO (VL_API_BIER_TABLE_ADD_DEL_REPLY);
114 }
115
116 static void
117 send_bier_table_details (vl_api_registration_t * reg,
118                          u32 context,
119                          const bier_table_t *bt)
120 {
121     vl_api_bier_table_details_t *mp;
122
123     mp = vl_msg_api_alloc(sizeof(*mp));
124     if (!mp)
125         return;
126     memset(mp, 0, sizeof(*mp));
127     mp->_vl_msg_id = ntohs(VL_API_BIER_TABLE_DETAILS);
128     mp->context = context;
129
130     mp->bt_label = bt->bt_ll;
131     mp->bt_tbl_id.bt_set = bt->bt_id.bti_set;
132     mp->bt_tbl_id.bt_sub_domain = bt->bt_id.bti_sub_domain;
133     mp->bt_tbl_id.bt_hdr_len_id = bt->bt_id.bti_hdr_len;
134
135     vl_api_send_msg (reg, (u8 *) mp);
136 }
137
138 static void
139 vl_api_bier_table_dump_t_handler (vl_api_bier_table_dump_t * mp)
140 {
141     vl_api_registration_t *reg;
142     bier_table_t *bt;
143
144     reg = vl_api_client_index_to_registration (mp->client_index);
145     if (!reg)
146       return;
147
148     pool_foreach(bt, bier_table_pool,
149     ({
150         /*
151          * skip the ecmp tables.
152          */
153         if (bier_table_is_main(bt))
154         {
155             send_bier_table_details(reg, mp->context, bt);
156         }
157     }));
158 }
159
160 static void
161 vl_api_bier_route_add_del_t_handler (vl_api_bier_route_add_del_t * mp)
162 {
163     vl_api_bier_route_add_del_reply_t *rmp;
164     fib_route_path_t *brpaths, *brpath;
165     vnet_main_t *vnm;
166     bier_bp_t bp;
167     int rv = 0;
168     u8 ii;
169
170     vnm = vnet_get_main ();
171     vnm->api_errno = 0;
172     bp = ntohl(mp->br_bp);
173     brpaths = NULL;
174
175     if (mp->br_tbl_id.bt_hdr_len_id >= BIER_HDR_LEN_2048)
176     {
177         rv = VNET_API_ERROR_BIER_BSL_UNSUP;
178         goto done;
179     }
180     if (0 == bp || bp > BIER_BP_MAX)
181     {
182         rv = -1;
183         goto done;
184     }
185
186     bier_table_id_t bti = {
187         .bti_set = mp->br_tbl_id.bt_set,
188         .bti_sub_domain = mp->br_tbl_id.bt_sub_domain,
189         .bti_hdr_len = mp->br_tbl_id.bt_hdr_len_id,
190         .bti_type = BIER_TABLE_MPLS_SPF,
191         .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
192     };
193
194     vec_validate(brpaths, mp->br_n_paths - 1);
195
196     vec_foreach_index(ii, brpaths)
197     {
198         brpath = &brpaths[ii];
199         rv = fib_path_api_parse(&mp->br_paths[ii], brpath);
200
201         if (0 != rv)
202         {
203             goto done;
204         }
205     }
206
207     if (mp->br_is_add)
208     {
209         bier_table_route_add(&bti, bp, brpaths);
210     }
211     else
212     {
213         bier_table_route_remove(&bti, bp, brpaths);
214     }
215     vec_free(brpaths);
216
217 done:
218     rv = (rv == 0) ? vnm->api_errno : rv;
219
220     REPLY_MACRO (VL_API_BIER_ROUTE_ADD_DEL_REPLY);
221 }
222
223 typedef struct bier_route_details_walk_t_
224 {
225     vl_api_registration_t * reg;
226     u32 context;
227 } bier_route_details_walk_t;
228
229 static void
230 send_bier_route_details (const bier_table_t *bt,
231                          const bier_entry_t *be,
232                          void *args)
233 {
234     fib_route_path_encode_t *api_rpaths = NULL, *api_rpath;
235     bier_route_details_walk_t *ctx = args;
236     vl_api_bier_route_details_t *mp;
237     vl_api_fib_path_t *fp;
238     u32 n_paths, m_size;
239
240     n_paths = fib_path_list_get_n_paths(be->be_path_list);
241     m_size = sizeof(*mp) + (n_paths * sizeof(vl_api_fib_path_t));
242     mp = vl_msg_api_alloc(m_size);
243     if (!mp)
244         return;
245
246     memset(mp, 0, m_size);
247     mp->_vl_msg_id = ntohs(VL_API_BIER_ROUTE_DETAILS);
248     mp->context = ctx->context;
249
250     mp->br_tbl_id.bt_set = bt->bt_id.bti_set;
251     mp->br_tbl_id.bt_sub_domain = bt->bt_id.bti_sub_domain;
252     mp->br_tbl_id.bt_hdr_len_id = bt->bt_id.bti_hdr_len;
253     mp->br_bp = htons(be->be_bp);
254     mp->br_n_paths = htonl(n_paths);
255
256     fib_path_list_walk(be->be_path_list, fib_path_encode, &api_rpaths);
257
258     fp = mp->br_paths;
259     vec_foreach (api_rpath, api_rpaths)
260     {
261         fib_api_path_encode(api_rpath, fp);
262         fp++;
263     }
264
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     memset(mp, 0, sizeof(*mp)+n_bytes);
366     mp->_vl_msg_id = ntohs(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     memset(mp, 0, sizeof(*mp));
433     mp->_vl_msg_id = ntohs(VL_API_BIER_DISP_TABLE_DETAILS);
434     mp->context = context;
435
436     mp->bdt_tbl_id = htonl(bdt->bdt_table_id);
437
438     vl_api_send_msg (reg, (u8 *) mp);
439 }
440
441 static void
442 vl_api_bier_disp_table_dump_t_handler (vl_api_bier_disp_table_dump_t * mp)
443 {
444     vl_api_registration_t *reg;
445     bier_disp_table_t *bdt;
446
447     reg = vl_api_client_index_to_registration (mp->client_index);
448     if (!reg)
449       return;
450
451     pool_foreach(bdt, bier_disp_table_pool,
452     ({
453         send_bier_disp_table_details(reg, mp->context, bdt);
454     }));
455 }
456
457 static void
458 vl_api_bier_disp_entry_add_del_t_handler (vl_api_bier_disp_entry_add_del_t * mp)
459 {
460     vl_api_bier_disp_entry_add_del_reply_t *rmp;
461     fib_route_path_t *brps = NULL, *brp;
462     vnet_main_t *vnm;
463     bier_bp_t bp;
464     u32 table_id;
465     int rv = 0;
466     u32 ii;
467
468     vnm = vnet_get_main ();
469     vnm->api_errno = 0;
470     table_id = ntohl(mp->bde_tbl_id);
471     bp = ntohs(mp->bde_bp);
472
473     /*
474      * BP=0 is the default route
475      */
476     if (bp > 0xffff)
477     {
478         rv = -1;
479         goto done;
480     }
481
482     vec_validate(brps, mp->bde_n_paths - 1);
483     vec_foreach_index(ii, brps)
484     {
485         brp = &brps[ii];
486         brp->frp_fib_index = ntohl(mp->bde_paths[ii].table_id);
487         brp->frp_sw_if_index = ntohl(mp->bde_paths[ii].sw_if_index);
488
489         if (~0 != ntohl(mp->bde_paths[ii].rpf_id))
490         {
491             brp->frp_flags = FIB_ROUTE_PATH_RPF_ID;
492             brp->frp_rpf_id = ntohl(mp->bde_paths[ii].rpf_id);
493         }
494
495         if (0 == mp->bde_paths[ii].afi)
496         {
497             clib_memcpy (&brp->frp_addr.ip4,
498                          mp->bde_paths[ii].next_hop,
499                          sizeof (brp->frp_addr.ip4));
500         }
501         else
502         {
503             clib_memcpy (&brp->frp_addr.ip6,
504                          mp->bde_paths[ii].next_hop,
505                          sizeof (brp->frp_addr.ip6));
506         }
507         if (ip46_address_is_zero(&brp->frp_addr))
508         {
509             index_t fti;
510
511             switch (mp->bde_payload_proto)
512             {
513             case BIER_HDR_PROTO_INVALID:
514             case BIER_HDR_PROTO_MPLS_DOWN_STREAM:
515             case BIER_HDR_PROTO_MPLS_UP_STREAM:
516             case BIER_HDR_PROTO_ETHERNET:
517             case BIER_HDR_PROTO_VXLAN:
518             case BIER_HDR_PROTO_CTRL:
519             case BIER_HDR_PROTO_OAM:
520                 rv = VNET_API_ERROR_UNSUPPORTED;
521                 goto done;
522                 break;
523             case BIER_HDR_PROTO_IPV4:
524             case BIER_HDR_PROTO_IPV6:
525             {
526                 fib_protocol_t fproto;
527
528                 fproto = (mp->bde_payload_proto == BIER_HDR_PROTO_IPV4 ?
529                           FIB_PROTOCOL_IP4 :
530                           FIB_PROTOCOL_IP6);
531
532                 if (brp->frp_flags & FIB_ROUTE_PATH_RPF_ID)
533                 {
534                     fti = mfib_table_find (fproto,
535                                            ntohl (mp->bde_paths[ii].table_id));
536                 }
537                 else
538                 {
539                     fti = fib_table_find (fproto,
540                                           ntohl (mp->bde_paths[ii].table_id));
541                 }
542
543                 if (INDEX_INVALID != fti)
544                 {
545                     brp->frp_fib_index = fti;
546                 }
547                 else
548                 {
549                     rv = VNET_API_ERROR_NO_SUCH_FIB;
550                     goto done;
551                 }
552                 break;
553             }
554             }
555         }
556     }
557
558     if (mp->bde_is_add)
559     {
560         bier_disp_table_entry_path_add(table_id, bp,
561                                        mp->bde_payload_proto,
562                                        brps);
563     }
564     else
565     {
566         bier_disp_table_entry_path_remove(table_id, bp,
567                                           mp->bde_payload_proto,
568                                           brps);
569     }
570
571 done:
572     vec_free(brps);
573     rv = (rv == 0) ? vnm->api_errno : rv;
574
575     REPLY_MACRO (VL_API_BIER_DISP_ENTRY_ADD_DEL_REPLY);
576 }
577
578 typedef struct bier_disp_entry_details_walk_t_
579 {
580     vl_api_registration_t * reg;
581     u32 context;
582 } bier_disp_entry_details_walk_t;
583
584 static void
585 send_bier_disp_entry_details (const bier_disp_table_t *bdt,
586                               const bier_disp_entry_t *bde,
587                               u16 bp,
588                               void *args)
589 {
590     fib_route_path_encode_t *api_rpaths = NULL, *api_rpath;
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         if (INDEX_INVALID != pl)
601         {
602             n_paths = fib_path_list_get_n_paths(pl);
603             m_size = sizeof(*mp) + (n_paths * sizeof(vl_api_fib_path_t));
604             mp = vl_msg_api_alloc(m_size);
605             if (!mp)
606                 return;
607
608             memset(mp, 0, m_size);
609             mp->_vl_msg_id = ntohs(VL_API_BIER_DISP_ENTRY_DETAILS);
610             mp->context = ctx->context;
611
612             mp->bde_tbl_id = htonl(bdt->bdt_table_id);
613             mp->bde_n_paths = htonl(n_paths);
614             mp->bde_payload_proto = pproto;
615             mp->bde_bp = htons(bp);
616
617             fib_path_list_walk(pl, fib_path_encode, &api_rpaths);
618
619             fp = mp->bde_paths;
620             vec_foreach (api_rpath, api_rpaths)
621             {
622                 fib_api_path_encode(api_rpath, fp);
623                 fp++;
624             }
625
626             vl_api_send_msg (ctx->reg, (u8 *) mp);
627         }
628     }
629 }
630
631 static void
632 vl_api_bier_disp_entry_dump_t_handler (vl_api_bier_disp_entry_dump_t * mp)
633 {
634     vl_api_registration_t *reg;
635
636     reg = vl_api_client_index_to_registration (mp->client_index);
637     if (!reg)
638       return;
639
640     bier_disp_entry_details_walk_t ctx = {
641         .reg = reg,
642         .context = mp->context,
643     };
644     bier_disp_table_walk(ntohl(mp->bde_tbl_id),
645                          send_bier_disp_entry_details,
646                          &ctx);
647 }
648
649 #define vl_msg_name_crc_list
650 #include <vnet/bier/bier.api.h>
651 #undef vl_msg_name_crc_list
652
653 static void
654 setup_message_id_table (api_main_t * am)
655 {
656 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
657     foreach_vl_msg_name_crc_bier;
658 #undef _
659 }
660
661 static clib_error_t *
662 bier_api_hookup (vlib_main_t * vm)
663 {
664     api_main_t *am = &api_main;
665
666 #define _(N,n)                                          \
667     vl_msg_api_set_handlers(VL_API_##N, #n,             \
668                             vl_api_##n##_t_handler,     \
669                             vl_noop_handler,            \
670                             vl_api_##n##_t_endian,      \
671                             vl_api_##n##_t_print,       \
672                             sizeof(vl_api_##n##_t), 1);
673     foreach_bier_api_msg;
674 #undef _
675
676     /*
677      * Set up the (msg_name, crc, message-id) table
678      */
679     setup_message_id_table (am);
680
681     return 0;
682 }
683
684 VLIB_API_INIT_FUNCTION (bier_api_hookup);