Remove c-11 memcpy checks from perf-critical code
[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     clib_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_replace)
208     {
209         if (0 == vec_len(brpaths))
210         {
211             bier_table_route_delete(&bti, bp);
212         }
213         else
214         {
215             bier_table_route_path_update(&bti, bp, brpaths);
216         }
217     }
218     else if (mp->br_is_add)
219     {
220         bier_table_route_path_add(&bti, bp, brpaths);
221     }
222     else
223     {
224         bier_table_route_path_remove(&bti, bp, brpaths);
225     }
226     vec_free(brpaths);
227
228 done:
229     rv = (rv == 0) ? vnm->api_errno : rv;
230
231     REPLY_MACRO (VL_API_BIER_ROUTE_ADD_DEL_REPLY);
232 }
233
234 typedef struct bier_route_details_walk_t_
235 {
236     vl_api_registration_t * reg;
237     u32 context;
238 } bier_route_details_walk_t;
239
240 static void
241 send_bier_route_details (const bier_table_t *bt,
242                          const bier_entry_t *be,
243                          void *args)
244 {
245     fib_route_path_encode_t *api_rpaths = NULL, *api_rpath;
246     bier_route_details_walk_t *ctx = args;
247     vl_api_bier_route_details_t *mp;
248     vl_api_fib_path_t *fp;
249     u32 n_paths, m_size;
250
251     n_paths = fib_path_list_get_n_paths(be->be_path_list);
252     m_size = sizeof(*mp) + (n_paths * sizeof(vl_api_fib_path_t));
253     mp = vl_msg_api_alloc(m_size);
254     if (!mp)
255         return;
256
257     clib_memset(mp, 0, m_size);
258     mp->_vl_msg_id = ntohs(VL_API_BIER_ROUTE_DETAILS);
259     mp->context = ctx->context;
260
261     mp->br_tbl_id.bt_set = bt->bt_id.bti_set;
262     mp->br_tbl_id.bt_sub_domain = bt->bt_id.bti_sub_domain;
263     mp->br_tbl_id.bt_hdr_len_id = bt->bt_id.bti_hdr_len;
264     mp->br_bp = htons(be->be_bp);
265     mp->br_n_paths = htonl(n_paths);
266
267     fib_path_list_walk(be->be_path_list, fib_path_encode, &api_rpaths);
268
269     fp = mp->br_paths;
270     vec_foreach (api_rpath, api_rpaths)
271     {
272         fib_api_path_encode(api_rpath, fp);
273         fp++;
274     }
275
276     vl_api_send_msg (ctx->reg, (u8 *) mp);
277 }
278
279 static void
280 vl_api_bier_route_dump_t_handler (vl_api_bier_route_dump_t * mp)
281 {
282     vl_api_registration_t *reg;
283
284     reg = vl_api_client_index_to_registration (mp->client_index);
285     if (!reg)
286       return;
287
288     bier_table_id_t bti = {
289         .bti_set = mp->br_tbl_id.bt_set,
290         .bti_sub_domain = mp->br_tbl_id.bt_sub_domain,
291         .bti_hdr_len = mp->br_tbl_id.bt_hdr_len_id,
292         .bti_type = BIER_TABLE_MPLS_SPF,
293         .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
294     };
295     bier_route_details_walk_t ctx = {
296         .reg = reg,
297         .context = mp->context,
298     };
299     bier_table_walk(&bti, send_bier_route_details, &ctx);
300 }
301
302 static void
303 vl_api_bier_imp_add_t_handler (vl_api_bier_imp_add_t * mp)
304 {
305     vl_api_bier_imp_add_reply_t *rmp;
306     vnet_main_t *vnm;
307     index_t bii = ~0;
308     int rv = 0;
309
310     vnm = vnet_get_main ();
311     vnm->api_errno = 0;
312
313     /*
314      * The BSL support by VPP is limited to the size of the
315      * available space in the vlib_buffer_t
316      */
317     if (mp->bi_tbl_id.bt_hdr_len_id >= BIER_HDR_LEN_2048)
318     {
319         rv = VNET_API_ERROR_BIER_BSL_UNSUP;
320     }
321     else
322     {
323         bier_table_id_t bti = {
324             .bti_set = mp->bi_tbl_id.bt_set,
325             .bti_sub_domain = mp->bi_tbl_id.bt_sub_domain,
326             .bti_hdr_len = mp->bi_tbl_id.bt_hdr_len_id,
327             .bti_type = BIER_TABLE_MPLS_SPF,
328             .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
329         };
330         bier_bit_string_t bs = {
331             .bbs_len = mp->bi_n_bytes,
332             .bbs_buckets = mp->bi_bytes,
333         };
334
335         bii = bier_imp_add_or_lock(&bti, ntohs(mp->bi_src), &bs);
336     }
337
338     REPLY_MACRO2 (VL_API_BIER_IMP_ADD_REPLY,
339     ({
340         rmp->bi_index = ntohl (bii);
341     }));
342 }
343
344 static void
345 vl_api_bier_imp_del_t_handler (vl_api_bier_imp_del_t * mp)
346 {
347     vl_api_bier_imp_del_reply_t *rmp;
348     vnet_main_t *vnm;
349     int rv = 0;
350
351     vnm = vnet_get_main ();
352     vnm->api_errno = 0;
353
354     bier_imp_unlock(ntohl(mp->bi_index));
355
356     REPLY_MACRO(VL_API_BIER_IMP_DEL_REPLY);
357 }
358
359 static void
360 send_bier_imp_details (vl_api_registration_t * reg,
361                        u32 context,
362                        const bier_imp_t *bi)
363 {
364     vl_api_bier_imp_details_t *mp;
365     bier_hdr_t copy;
366     u8 n_bytes;
367
368     copy = bi->bi_hdr;
369     bier_hdr_ntoh(&copy);
370
371     n_bytes = bier_hdr_len_id_to_num_bytes(
372                   bier_hdr_get_len_id(&copy));
373     mp = vl_msg_api_alloc(sizeof(*mp) + n_bytes);
374     if (!mp)
375         return;
376     clib_memset(mp, 0, sizeof(*mp)+n_bytes);
377     mp->_vl_msg_id = ntohs(VL_API_BIER_IMP_DETAILS);
378     mp->context = context;
379
380     mp->bi_tbl_id.bt_set = bi->bi_tbl.bti_set;
381     mp->bi_tbl_id.bt_sub_domain = bi->bi_tbl.bti_sub_domain;
382     mp->bi_tbl_id.bt_hdr_len_id = bi->bi_tbl.bti_hdr_len;
383
384     mp->bi_src = htons(bier_hdr_get_src_id(&copy));
385     mp->bi_n_bytes = n_bytes;
386     memcpy(mp->bi_bytes, bi->bi_bits, n_bytes);
387
388     vl_api_send_msg (reg, (u8 *) mp);
389 }
390
391 static void
392 vl_api_bier_imp_dump_t_handler (vl_api_bier_imp_dump_t * mp)
393 {
394     vl_api_registration_t *reg;
395     bier_imp_t *bi;
396
397     reg = vl_api_client_index_to_registration (mp->client_index);
398     if (!reg)
399       return;
400
401     pool_foreach(bi, bier_imp_pool,
402     ({
403         send_bier_imp_details(reg, mp->context, bi);
404     }));
405 }
406
407 static void
408 vl_api_bier_disp_table_add_del_t_handler (vl_api_bier_disp_table_add_del_t * mp)
409 {
410     vl_api_bier_disp_table_add_del_reply_t *rmp;
411     vnet_main_t *vnm;
412     u32 table_id;
413     int rv;
414
415     vnm = vnet_get_main ();
416     vnm->api_errno = 0;
417     table_id = ntohl(mp->bdt_tbl_id);
418
419     if (mp->bdt_is_add)
420     {
421         bier_disp_table_add_or_lock(table_id);
422     }
423     else
424     {
425         bier_disp_table_unlock_w_table_id(table_id);
426     }
427
428     rv = vnm->api_errno;
429
430     REPLY_MACRO (VL_API_BIER_DISP_TABLE_ADD_DEL_REPLY);
431 }
432
433 static void
434 send_bier_disp_table_details (vl_api_registration_t * reg,
435                               u32 context,
436                               const bier_disp_table_t *bdt)
437 {
438     vl_api_bier_disp_table_details_t *mp;
439
440     mp = vl_msg_api_alloc(sizeof(*mp));
441     if (!mp)
442         return;
443     clib_memset(mp, 0, sizeof(*mp));
444     mp->_vl_msg_id = ntohs(VL_API_BIER_DISP_TABLE_DETAILS);
445     mp->context = context;
446
447     mp->bdt_tbl_id = htonl(bdt->bdt_table_id);
448
449     vl_api_send_msg (reg, (u8 *) mp);
450 }
451
452 static void
453 vl_api_bier_disp_table_dump_t_handler (vl_api_bier_disp_table_dump_t * mp)
454 {
455     vl_api_registration_t *reg;
456     bier_disp_table_t *bdt;
457
458     reg = vl_api_client_index_to_registration (mp->client_index);
459     if (!reg)
460       return;
461
462     pool_foreach(bdt, bier_disp_table_pool,
463     ({
464         send_bier_disp_table_details(reg, mp->context, bdt);
465     }));
466 }
467
468 static void
469 vl_api_bier_disp_entry_add_del_t_handler (vl_api_bier_disp_entry_add_del_t * mp)
470 {
471     vl_api_bier_disp_entry_add_del_reply_t *rmp;
472     fib_route_path_t *brps = NULL, *brp;
473     vnet_main_t *vnm;
474     bier_bp_t bp;
475     u32 table_id;
476     int rv = 0;
477     u32 ii;
478
479     vnm = vnet_get_main ();
480     vnm->api_errno = 0;
481     table_id = ntohl(mp->bde_tbl_id);
482     bp = ntohs(mp->bde_bp);
483
484     /*
485      * BP=0 is the default route
486      */
487     if (bp > 0xffff)
488     {
489         rv = -1;
490         goto done;
491     }
492
493     vec_validate(brps, mp->bde_n_paths - 1);
494     vec_foreach_index(ii, brps)
495     {
496         brp = &brps[ii];
497         brp->frp_fib_index = ntohl(mp->bde_paths[ii].table_id);
498         brp->frp_sw_if_index = ntohl(mp->bde_paths[ii].sw_if_index);
499
500         if (~0 != ntohl(mp->bde_paths[ii].rpf_id))
501         {
502             brp->frp_flags = FIB_ROUTE_PATH_RPF_ID;
503             brp->frp_rpf_id = ntohl(mp->bde_paths[ii].rpf_id);
504         }
505
506         if (0 == mp->bde_paths[ii].afi)
507         {
508             clib_memcpy_fast (&brp->frp_addr.ip4,
509                          mp->bde_paths[ii].next_hop,
510                          sizeof (brp->frp_addr.ip4));
511         }
512         else
513         {
514             clib_memcpy_fast (&brp->frp_addr.ip6,
515                          mp->bde_paths[ii].next_hop,
516                          sizeof (brp->frp_addr.ip6));
517         }
518         if (ip46_address_is_zero(&brp->frp_addr))
519         {
520             index_t fti;
521
522             switch (mp->bde_payload_proto)
523             {
524             case BIER_HDR_PROTO_INVALID:
525             case BIER_HDR_PROTO_MPLS_DOWN_STREAM:
526             case BIER_HDR_PROTO_MPLS_UP_STREAM:
527             case BIER_HDR_PROTO_ETHERNET:
528             case BIER_HDR_PROTO_VXLAN:
529             case BIER_HDR_PROTO_CTRL:
530             case BIER_HDR_PROTO_OAM:
531                 rv = VNET_API_ERROR_UNSUPPORTED;
532                 goto done;
533                 break;
534             case BIER_HDR_PROTO_IPV4:
535             case BIER_HDR_PROTO_IPV6:
536             {
537                 fib_protocol_t fproto;
538
539                 fproto = (mp->bde_payload_proto == BIER_HDR_PROTO_IPV4 ?
540                           FIB_PROTOCOL_IP4 :
541                           FIB_PROTOCOL_IP6);
542
543                 if (brp->frp_flags & FIB_ROUTE_PATH_RPF_ID)
544                 {
545                     fti = mfib_table_find (fproto,
546                                            ntohl (mp->bde_paths[ii].table_id));
547                 }
548                 else
549                 {
550                     fti = fib_table_find (fproto,
551                                           ntohl (mp->bde_paths[ii].table_id));
552                 }
553
554                 if (INDEX_INVALID != fti)
555                 {
556                     brp->frp_fib_index = fti;
557                 }
558                 else
559                 {
560                     rv = VNET_API_ERROR_NO_SUCH_FIB;
561                     goto done;
562                 }
563                 break;
564             }
565             }
566         }
567     }
568
569     if (mp->bde_is_add)
570     {
571         bier_disp_table_entry_path_add(table_id, bp,
572                                        mp->bde_payload_proto,
573                                        brps);
574     }
575     else
576     {
577         bier_disp_table_entry_path_remove(table_id, bp,
578                                           mp->bde_payload_proto,
579                                           brps);
580     }
581
582 done:
583     vec_free(brps);
584     rv = (rv == 0) ? vnm->api_errno : rv;
585
586     REPLY_MACRO (VL_API_BIER_DISP_ENTRY_ADD_DEL_REPLY);
587 }
588
589 typedef struct bier_disp_entry_details_walk_t_
590 {
591     vl_api_registration_t * reg;
592     u32 context;
593 } bier_disp_entry_details_walk_t;
594
595 static void
596 send_bier_disp_entry_details (const bier_disp_table_t *bdt,
597                               const bier_disp_entry_t *bde,
598                               u16 bp,
599                               void *args)
600 {
601     fib_route_path_encode_t *api_rpaths = NULL, *api_rpath;
602     bier_disp_entry_details_walk_t *ctx = args;
603     vl_api_bier_disp_entry_details_t *mp;
604     bier_hdr_proto_id_t pproto;
605     vl_api_fib_path_t *fp;
606     u32 n_paths, m_size;
607
608     FOR_EACH_BIER_HDR_PROTO(pproto)
609     {
610         fib_node_index_t pl = bde->bde_pl[pproto];
611         if (INDEX_INVALID != pl)
612         {
613             n_paths = fib_path_list_get_n_paths(pl);
614             m_size = sizeof(*mp) + (n_paths * sizeof(vl_api_fib_path_t));
615             mp = vl_msg_api_alloc(m_size);
616             if (!mp)
617                 return;
618
619             clib_memset(mp, 0, m_size);
620             mp->_vl_msg_id = ntohs(VL_API_BIER_DISP_ENTRY_DETAILS);
621             mp->context = ctx->context;
622
623             mp->bde_tbl_id = htonl(bdt->bdt_table_id);
624             mp->bde_n_paths = htonl(n_paths);
625             mp->bde_payload_proto = pproto;
626             mp->bde_bp = htons(bp);
627
628             fib_path_list_walk(pl, fib_path_encode, &api_rpaths);
629
630             fp = mp->bde_paths;
631             vec_foreach (api_rpath, api_rpaths)
632             {
633                 fib_api_path_encode(api_rpath, fp);
634                 fp++;
635             }
636
637             vl_api_send_msg (ctx->reg, (u8 *) mp);
638         }
639     }
640 }
641
642 static void
643 vl_api_bier_disp_entry_dump_t_handler (vl_api_bier_disp_entry_dump_t * mp)
644 {
645     vl_api_registration_t *reg;
646
647     reg = vl_api_client_index_to_registration (mp->client_index);
648     if (!reg)
649       return;
650
651     bier_disp_entry_details_walk_t ctx = {
652         .reg = reg,
653         .context = mp->context,
654     };
655     bier_disp_table_walk(ntohl(mp->bde_tbl_id),
656                          send_bier_disp_entry_details,
657                          &ctx);
658 }
659
660 #define vl_msg_name_crc_list
661 #include <vnet/bier/bier.api.h>
662 #undef vl_msg_name_crc_list
663
664 static void
665 setup_message_id_table (api_main_t * am)
666 {
667 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
668     foreach_vl_msg_name_crc_bier;
669 #undef _
670 }
671
672 static clib_error_t *
673 bier_api_hookup (vlib_main_t * vm)
674 {
675     api_main_t *am = &api_main;
676
677 #define _(N,n)                                          \
678     vl_msg_api_set_handlers(VL_API_##N, #n,             \
679                             vl_api_##n##_t_handler,     \
680                             vl_noop_handler,            \
681                             vl_api_##n##_t_endian,      \
682                             vl_api_##n##_t_print,       \
683                             sizeof(vl_api_##n##_t), 1);
684     foreach_bier_api_msg;
685 #undef _
686
687     /*
688      * Set up the (msg_name, crc, message-id) table
689      */
690     setup_message_id_table (am);
691
692     return 0;
693 }
694
695 VLIB_API_INIT_FUNCTION (bier_api_hookup);