Line data Source code
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 14 : 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 14 : vnm = vnet_get_main ();
57 14 : vnm->api_errno = 0;
58 :
59 14 : if (mp->bt_tbl_id.bt_hdr_len_id >= BIER_HDR_LEN_2048)
60 : {
61 0 : rv = VNET_API_ERROR_BIER_BSL_UNSUP;
62 : }
63 : else
64 : {
65 14 : bier_table_id_t bti = {
66 14 : .bti_set = mp->bt_tbl_id.bt_set,
67 14 : .bti_sub_domain = mp->bt_tbl_id.bt_sub_domain,
68 14 : .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 14 : if (mp->bt_is_add)
74 : {
75 7 : 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 7 : if ((0 == label) || (~0 == label))
82 : {
83 0 : label = MPLS_LABEL_INVALID;
84 : }
85 7 : bier_table_add_or_lock(&bti, label);
86 : }
87 : else
88 : {
89 7 : bier_table_unlock(&bti);
90 : }
91 :
92 14 : rv = vnm->api_errno;
93 : }
94 :
95 14 : REPLY_MACRO (VL_API_BIER_TABLE_ADD_DEL_REPLY);
96 : }
97 :
98 : static void
99 7 : 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 7 : mp = vl_msg_api_alloc(sizeof(*mp));
106 7 : if (!mp)
107 0 : return;
108 7 : clib_memset(mp, 0, sizeof(*mp));
109 7 : mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_BIER_TABLE_DETAILS);
110 7 : mp->context = context;
111 :
112 7 : mp->bt_label = bt->bt_ll;
113 7 : mp->bt_tbl_id.bt_set = bt->bt_id.bti_set;
114 7 : mp->bt_tbl_id.bt_sub_domain = bt->bt_id.bti_sub_domain;
115 7 : mp->bt_tbl_id.bt_hdr_len_id = bt->bt_id.bti_hdr_len;
116 :
117 7 : vl_api_send_msg (reg, (u8 *) mp);
118 : }
119 :
120 : static void
121 14 : 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 14 : reg = vl_api_client_index_to_registration (mp->client_index);
127 14 : if (!reg)
128 0 : return;
129 :
130 133 : pool_foreach (bt, bier_table_pool)
131 : {
132 : /*
133 : * skip the ecmp tables.
134 : */
135 119 : if (bier_table_is_main(bt))
136 : {
137 7 : send_bier_table_details(reg, mp->context, bt);
138 : }
139 : }
140 : }
141 :
142 : static void
143 147 : 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 147 : int rv = 0;
150 : u8 ii;
151 :
152 147 : vnm = vnet_get_main ();
153 147 : vnm->api_errno = 0;
154 147 : bp = ntohl(mp->br_route.br_bp);
155 147 : brpaths = NULL;
156 :
157 147 : if (mp->br_route.br_tbl_id.bt_hdr_len_id >= BIER_HDR_LEN_2048)
158 : {
159 0 : rv = VNET_API_ERROR_BIER_BSL_UNSUP;
160 0 : goto done;
161 : }
162 147 : if (0 == bp || bp > BIER_BP_MAX)
163 : {
164 0 : rv = -1;
165 0 : goto done;
166 : }
167 :
168 147 : bier_table_id_t bti = {
169 147 : .bti_set = mp->br_route.br_tbl_id.bt_set,
170 147 : .bti_sub_domain = mp->br_route.br_tbl_id.bt_sub_domain,
171 147 : .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 147 : vec_validate(brpaths, mp->br_route.br_n_paths - 1);
177 :
178 297 : vec_foreach_index(ii, brpaths)
179 : {
180 150 : brpath = &brpaths[ii];
181 150 : rv = fib_api_path_decode(&mp->br_route.br_paths[ii], brpath);
182 :
183 150 : if (0 != rv)
184 : {
185 0 : goto done;
186 : }
187 : }
188 :
189 147 : if (mp->br_is_replace)
190 : {
191 2 : if (0 == vec_len(brpaths))
192 : {
193 1 : bier_table_route_delete(&bti, bp);
194 : }
195 : else
196 : {
197 1 : bier_table_route_path_update(&bti, bp, brpaths);
198 : }
199 : }
200 145 : else if (mp->br_is_add)
201 : {
202 72 : bier_table_route_path_add(&bti, bp, brpaths);
203 : }
204 : else
205 : {
206 73 : bier_table_route_path_remove(&bti, bp, brpaths);
207 : }
208 147 : vec_free(brpaths);
209 :
210 147 : done:
211 147 : rv = (rv == 0) ? vnm->api_errno : rv;
212 :
213 147 : 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 11 : send_bier_route_details (const bier_table_t *bt,
224 : const bier_entry_t *be,
225 : void *args)
226 : {
227 11 : bier_route_details_walk_t *ctx = args;
228 : vl_api_bier_route_details_t *mp;
229 11 : 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 11 : n_paths = fib_path_list_get_n_paths(be->be_path_list);
237 11 : m_size = sizeof(*mp) + (n_paths * sizeof(vl_api_fib_path_t));
238 11 : mp = vl_msg_api_alloc(m_size);
239 11 : if (!mp)
240 0 : return;
241 :
242 11 : clib_memset(mp, 0, m_size);
243 11 : mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_BIER_ROUTE_DETAILS);
244 11 : mp->context = ctx->context;
245 :
246 11 : mp->br_route.br_tbl_id.bt_set = bt->bt_id.bti_set;
247 11 : mp->br_route.br_tbl_id.bt_sub_domain = bt->bt_id.bti_sub_domain;
248 11 : mp->br_route.br_tbl_id.bt_hdr_len_id = bt->bt_id.bti_hdr_len;
249 11 : mp->br_route.br_bp = htonl(be->be_bp);
250 11 : mp->br_route.br_n_paths = htonl(n_paths);
251 :
252 11 : fib_path_list_walk_w_ext(be->be_path_list,
253 : NULL,
254 : fib_path_encode,
255 : &path_ctx);
256 :
257 11 : fp = mp->br_route.br_paths;
258 22 : vec_foreach (rpath, path_ctx.rpaths)
259 : {
260 11 : fib_api_path_encode(rpath, fp);
261 11 : fp++;
262 : }
263 :
264 11 : vec_free(path_ctx.rpaths);
265 11 : vl_api_send_msg (ctx->reg, (u8 *) mp);
266 : }
267 :
268 : static void
269 79 : vl_api_bier_route_dump_t_handler (vl_api_bier_route_dump_t * mp)
270 : {
271 : vl_api_registration_t *reg;
272 :
273 79 : reg = vl_api_client_index_to_registration (mp->client_index);
274 79 : if (!reg)
275 0 : return;
276 :
277 79 : bier_table_id_t bti = {
278 79 : .bti_set = mp->br_tbl_id.bt_set,
279 79 : .bti_sub_domain = mp->br_tbl_id.bt_sub_domain,
280 79 : .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 79 : bier_route_details_walk_t ctx = {
285 : .reg = reg,
286 79 : .context = mp->context,
287 : };
288 79 : bier_table_walk(&bti, send_bier_route_details, &ctx);
289 : }
290 :
291 : static void
292 6 : 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 6 : index_t bii = ~0;
297 6 : int rv = 0;
298 :
299 6 : vnm = vnet_get_main ();
300 6 : 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 6 : if (mp->bi_tbl_id.bt_hdr_len_id >= BIER_HDR_LEN_2048)
307 : {
308 0 : rv = VNET_API_ERROR_BIER_BSL_UNSUP;
309 : }
310 : else
311 : {
312 6 : bier_table_id_t bti = {
313 6 : .bti_set = mp->bi_tbl_id.bt_set,
314 6 : .bti_sub_domain = mp->bi_tbl_id.bt_sub_domain,
315 6 : .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 6 : bier_bit_string_t bs = {
320 6 : .bbs_len = mp->bi_n_bytes,
321 6 : .bbs_buckets = mp->bi_bytes,
322 : };
323 :
324 6 : bii = bier_imp_add_or_lock(&bti, ntohs(mp->bi_src), &bs);
325 : }
326 :
327 6 : REPLY_MACRO2 (VL_API_BIER_IMP_ADD_REPLY,
328 : ({
329 : rmp->bi_index = ntohl (bii);
330 : }));
331 : }
332 :
333 : static void
334 6 : 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 6 : int rv = 0;
339 :
340 6 : vnm = vnet_get_main ();
341 6 : vnm->api_errno = 0;
342 :
343 6 : bier_imp_unlock(ntohl(mp->bi_index));
344 :
345 6 : REPLY_MACRO(VL_API_BIER_IMP_DEL_REPLY);
346 : }
347 :
348 : static void
349 10 : 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 10 : copy = bi->bi_hdr;
358 10 : bier_hdr_ntoh(©);
359 :
360 10 : n_bytes = bier_hdr_len_id_to_num_bytes(
361 10 : bier_hdr_get_len_id(©));
362 10 : mp = vl_msg_api_alloc(sizeof(*mp) + n_bytes);
363 10 : if (!mp)
364 0 : return;
365 10 : clib_memset(mp, 0, sizeof(*mp)+n_bytes);
366 10 : mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_BIER_IMP_DETAILS);
367 10 : mp->context = context;
368 :
369 10 : mp->bi_tbl_id.bt_set = bi->bi_tbl.bti_set;
370 10 : mp->bi_tbl_id.bt_sub_domain = bi->bi_tbl.bti_sub_domain;
371 10 : mp->bi_tbl_id.bt_hdr_len_id = bi->bi_tbl.bti_hdr_len;
372 :
373 10 : mp->bi_src = htons(bier_hdr_get_src_id(©));
374 10 : mp->bi_n_bytes = n_bytes;
375 10 : memcpy(mp->bi_bytes, bi->bi_bits, n_bytes);
376 :
377 10 : vl_api_send_msg (reg, (u8 *) mp);
378 : }
379 :
380 : static void
381 12 : 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 12 : reg = vl_api_client_index_to_registration (mp->client_index);
387 12 : if (!reg)
388 0 : return;
389 :
390 22 : pool_foreach (bi, bier_imp_pool)
391 : {
392 10 : send_bier_imp_details(reg, mp->context, bi);
393 : }
394 : }
395 :
396 : static void
397 6 : 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 6 : vnm = vnet_get_main ();
405 6 : vnm->api_errno = 0;
406 6 : table_id = ntohl(mp->bdt_tbl_id);
407 :
408 6 : if (mp->bdt_is_add)
409 : {
410 3 : bier_disp_table_add_or_lock(table_id);
411 : }
412 : else
413 : {
414 3 : bier_disp_table_unlock_w_table_id(table_id);
415 : }
416 :
417 6 : rv = vnm->api_errno;
418 :
419 6 : REPLY_MACRO (VL_API_BIER_DISP_TABLE_ADD_DEL_REPLY);
420 : }
421 :
422 : static void
423 3 : 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 3 : mp = vl_msg_api_alloc(sizeof(*mp));
430 3 : if (!mp)
431 0 : return;
432 3 : clib_memset(mp, 0, sizeof(*mp));
433 3 : mp->_vl_msg_id =
434 3 : ntohs (REPLY_MSG_ID_BASE + VL_API_BIER_DISP_TABLE_DETAILS);
435 3 : mp->context = context;
436 :
437 3 : mp->bdt_tbl_id = htonl(bdt->bdt_table_id);
438 :
439 3 : vl_api_send_msg (reg, (u8 *) mp);
440 : }
441 :
442 : static void
443 6 : 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 6 : reg = vl_api_client_index_to_registration (mp->client_index);
449 6 : if (!reg)
450 0 : return;
451 :
452 9 : pool_foreach (bdt, bier_disp_table_pool)
453 : {
454 3 : send_bier_disp_table_details(reg, mp->context, bdt);
455 : }
456 : }
457 :
458 : static void
459 10 : 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 10 : fib_route_path_t *brps = NULL, *brp;
463 : vnet_main_t *vnm;
464 : bier_bp_t bp;
465 : u32 table_id;
466 10 : int rv = 0;
467 : u32 ii;
468 :
469 10 : vnm = vnet_get_main ();
470 10 : vnm->api_errno = 0;
471 10 : table_id = ntohl(mp->bde_tbl_id);
472 10 : bp = ntohs(mp->bde_bp);
473 :
474 : /*
475 : * BP=0 is the default route
476 : */
477 10 : if (bp > 0xffff)
478 : {
479 0 : rv = -1;
480 0 : goto done;
481 : }
482 :
483 10 : vec_validate(brps, mp->bde_n_paths - 1);
484 20 : vec_foreach_index(ii, brps)
485 : {
486 10 : brp = &brps[ii];
487 10 : brp->frp_fib_index = ntohl(mp->bde_paths[ii].table_id);
488 10 : brp->frp_sw_if_index = ntohl(mp->bde_paths[ii].sw_if_index);
489 :
490 10 : if (~0 != ntohl(mp->bde_paths[ii].rpf_id))
491 : {
492 10 : brp->frp_flags = FIB_ROUTE_PATH_RPF_ID;
493 10 : brp->frp_rpf_id = ntohl(mp->bde_paths[ii].rpf_id);
494 : }
495 :
496 10 : if (FIB_API_PATH_NH_PROTO_IP4 == mp->bde_paths[ii].proto)
497 : {
498 10 : clib_memcpy (&brp->frp_addr.ip4,
499 : &mp->bde_paths[ii].nh.address.ip4,
500 : sizeof (brp->frp_addr.ip4));
501 : }
502 0 : else if (FIB_API_PATH_NH_PROTO_IP6 == mp->bde_paths[ii].proto)
503 : {
504 0 : clib_memcpy (&brp->frp_addr.ip6,
505 : &mp->bde_paths[ii].nh.address.ip6,
506 : sizeof (brp->frp_addr.ip6));
507 : }
508 10 : if (ip46_address_is_zero(&brp->frp_addr))
509 : {
510 : index_t fti;
511 :
512 10 : switch (mp->bde_payload_proto)
513 : {
514 0 : 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 0 : rv = VNET_API_ERROR_UNSUPPORTED;
522 0 : goto done;
523 : break;
524 10 : case BIER_HDR_PROTO_IPV4:
525 : case BIER_HDR_PROTO_IPV6:
526 : {
527 : fib_protocol_t fproto;
528 :
529 10 : fproto = (mp->bde_payload_proto == BIER_HDR_PROTO_IPV4 ?
530 10 : FIB_PROTOCOL_IP4 :
531 : FIB_PROTOCOL_IP6);
532 :
533 10 : if (brp->frp_flags & FIB_ROUTE_PATH_RPF_ID)
534 : {
535 10 : fti = mfib_table_find (fproto,
536 : ntohl (mp->bde_paths[ii].table_id));
537 : }
538 : else
539 : {
540 0 : fti = fib_table_find (fproto,
541 : ntohl (mp->bde_paths[ii].table_id));
542 : }
543 :
544 10 : if (INDEX_INVALID != fti)
545 : {
546 10 : brp->frp_fib_index = fti;
547 : }
548 : else
549 : {
550 0 : rv = VNET_API_ERROR_NO_SUCH_FIB;
551 0 : goto done;
552 : }
553 10 : break;
554 : }
555 : }
556 10 : }
557 : }
558 :
559 10 : if (mp->bde_is_add)
560 : {
561 5 : bier_disp_table_entry_path_add(table_id, bp,
562 5 : mp->bde_payload_proto,
563 : brps);
564 : }
565 : else
566 : {
567 5 : bier_disp_table_entry_path_remove(table_id, bp,
568 5 : mp->bde_payload_proto,
569 : brps);
570 : }
571 :
572 10 : done:
573 10 : vec_free(brps);
574 10 : rv = (rv == 0) ? vnm->api_errno : rv;
575 :
576 10 : 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 9 : 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 9 : 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 81 : FOR_EACH_BIER_HDR_PROTO(pproto)
598 : {
599 72 : fib_node_index_t pl = bde->bde_pl[pproto];
600 :
601 72 : if (INDEX_INVALID != pl)
602 : {
603 9 : fib_path_encode_ctx_t path_ctx = {
604 : .rpaths = NULL,
605 : };
606 : fib_route_path_t *rpath;
607 :
608 9 : n_paths = fib_path_list_get_n_paths(pl);
609 9 : m_size = sizeof(*mp) + (n_paths * sizeof(vl_api_fib_path_t));
610 9 : mp = vl_msg_api_alloc(m_size);
611 9 : if (!mp)
612 0 : return;
613 :
614 9 : clib_memset(mp, 0, m_size);
615 9 : mp->_vl_msg_id =
616 9 : ntohs (REPLY_MSG_ID_BASE + VL_API_BIER_DISP_ENTRY_DETAILS);
617 9 : mp->context = ctx->context;
618 :
619 9 : mp->bde_tbl_id = htonl (bdt->bdt_table_id);
620 9 : mp->bde_n_paths = htonl (n_paths);
621 9 : mp->bde_payload_proto = pproto;
622 9 : mp->bde_bp = htons (bp);
623 :
624 9 : fib_path_list_walk_w_ext (pl, NULL, fib_path_encode, &path_ctx);
625 :
626 9 : fp = mp->bde_paths;
627 18 : vec_foreach (rpath, path_ctx.rpaths)
628 : {
629 9 : fib_api_path_encode (rpath, fp);
630 9 : fp++;
631 : }
632 :
633 9 : vl_api_send_msg (ctx->reg, (u8 *) mp);
634 9 : vec_free (path_ctx.rpaths);
635 : }
636 : }
637 : }
638 :
639 : static void
640 10 : 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 10 : reg = vl_api_client_index_to_registration (mp->client_index);
645 10 : if (!reg)
646 0 : return;
647 :
648 10 : bier_disp_entry_details_walk_t ctx = {
649 : .reg = reg,
650 10 : .context = mp->context,
651 : };
652 10 : 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 559 : bier_api_hookup (vlib_main_t * vm)
661 : {
662 559 : bier_main.msg_id_base = setup_message_id_table ();
663 :
664 559 : return 0;
665 : }
666 :
667 19039 : VLIB_API_INIT_FUNCTION (bier_api_hookup);
|