Line data Source code
1 : /*
2 : *------------------------------------------------------------------
3 : * mpls_api.c - mpls 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/interface.h>
24 : #include <vnet/api_errno.h>
25 : #include <vnet/mpls/mpls.h>
26 : #include <vnet/mpls/mpls_tunnel.h>
27 : #include <vnet/fib/fib_table.h>
28 : #include <vnet/fib/fib_api.h>
29 : #include <vnet/fib/mpls_fib.h>
30 : #include <vnet/fib/fib_path_list.h>
31 : #include <vnet/ip/ip_types_api.h>
32 :
33 : #include <vnet/format_fns.h>
34 : #include <vnet/mpls/mpls.api_enum.h>
35 : #include <vnet/mpls/mpls.api_types.h>
36 :
37 : #define REPLY_MSG_ID_BASE mpls_main.msg_id_base
38 : #include <vlibapi/api_helper_macros.h>
39 :
40 : void
41 44 : mpls_table_delete (u32 table_id, u8 is_api)
42 : {
43 : u32 fib_index;
44 :
45 : /*
46 : * The MPLS defult table must also be explicitly created via the API.
47 : * So in contrast to IP, it gets no special treatment here.
48 : *
49 : * The API holds only one lock on the table.
50 : * i.e. it can be added many times via the API but needs to be
51 : * deleted only once.
52 : */
53 44 : fib_index = fib_table_find (FIB_PROTOCOL_MPLS, table_id);
54 :
55 44 : if (~0 != fib_index)
56 : {
57 44 : fib_table_unlock (fib_index,
58 : FIB_PROTOCOL_MPLS,
59 : (is_api ? FIB_SOURCE_API : FIB_SOURCE_CLI));
60 : }
61 44 : }
62 :
63 : void
64 82 : vl_api_mpls_table_add_del_t_handler (vl_api_mpls_table_add_del_t * mp)
65 : {
66 : vl_api_mpls_table_add_del_reply_t *rmp;
67 : vnet_main_t *vnm;
68 82 : int rv = 0;
69 :
70 82 : vnm = vnet_get_main ();
71 82 : vnm->api_errno = 0;
72 :
73 82 : if (mp->mt_is_add)
74 41 : mpls_table_create (ntohl (mp->mt_table.mt_table_id),
75 41 : 1, mp->mt_table.mt_name);
76 : else
77 41 : mpls_table_delete (ntohl (mp->mt_table.mt_table_id), 1);
78 :
79 : // NB: Nothing sets rv; none of the above returns an error
80 :
81 82 : REPLY_MACRO (VL_API_MPLS_TABLE_ADD_DEL_REPLY);
82 : }
83 :
84 : static int
85 278 : mpls_ip_bind_unbind_handler (vnet_main_t * vnm,
86 : vl_api_mpls_ip_bind_unbind_t * mp)
87 : {
88 : u32 mpls_fib_index, ip_fib_index;
89 : fib_prefix_t pfx;
90 :
91 : mpls_fib_index =
92 278 : fib_table_find (FIB_PROTOCOL_MPLS, ntohl (mp->mb_mpls_table_id));
93 :
94 278 : if (~0 == mpls_fib_index)
95 : {
96 0 : return VNET_API_ERROR_NO_SUCH_FIB;
97 : }
98 :
99 278 : ip_prefix_decode (&mp->mb_prefix, &pfx);
100 :
101 278 : ip_fib_index = fib_table_find (pfx.fp_proto, ntohl (mp->mb_ip_table_id));
102 278 : if (~0 == ip_fib_index)
103 0 : return VNET_API_ERROR_NO_SUCH_FIB;
104 :
105 278 : if (mp->mb_is_bind)
106 139 : fib_table_entry_local_label_add (ip_fib_index, &pfx,
107 : ntohl (mp->mb_label));
108 : else
109 139 : fib_table_entry_local_label_remove (ip_fib_index, &pfx,
110 : ntohl (mp->mb_label));
111 :
112 278 : return (0);
113 : }
114 :
115 : void
116 278 : vl_api_mpls_ip_bind_unbind_t_handler (vl_api_mpls_ip_bind_unbind_t * mp)
117 : {
118 : vl_api_mpls_ip_bind_unbind_reply_t *rmp;
119 : vnet_main_t *vnm;
120 : int rv;
121 :
122 278 : vnm = vnet_get_main ();
123 278 : vnm->api_errno = 0;
124 :
125 278 : rv = mpls_ip_bind_unbind_handler (vnm, mp);
126 278 : rv = (rv == 0) ? vnm->api_errno : rv;
127 :
128 278 : REPLY_MACRO (VL_API_MPLS_IP_BIND_UNBIND_REPLY);
129 : }
130 :
131 : static int
132 66 : mpls_route_add_del_t_handler (vnet_main_t * vnm,
133 : vl_api_mpls_route_add_del_t * mp,
134 : u32 * stats_index)
135 : {
136 66 : fib_route_path_t *rpaths = NULL, *rpath;
137 : vl_api_fib_path_t *apath;
138 : u32 fib_index;
139 : int rv, ii;
140 :
141 66 : fib_prefix_t pfx = {
142 : .fp_len = 21,
143 : .fp_proto = FIB_PROTOCOL_MPLS,
144 66 : .fp_eos = mp->mr_route.mr_eos,
145 66 : .fp_label = ntohl (mp->mr_route.mr_label),
146 : };
147 66 : if (pfx.fp_eos)
148 : {
149 52 : pfx.fp_payload_proto = mp->mr_route.mr_eos_proto;
150 : }
151 : else
152 : {
153 14 : pfx.fp_payload_proto = DPO_PROTO_MPLS;
154 : }
155 :
156 66 : rv = fib_api_table_id_decode (FIB_PROTOCOL_MPLS,
157 : ntohl (mp->mr_route.mr_table_id), &fib_index);
158 66 : if (0 != rv)
159 0 : goto out;
160 :
161 66 : vec_validate (rpaths, mp->mr_route.mr_n_paths - 1);
162 :
163 138 : for (ii = 0; ii < mp->mr_route.mr_n_paths; ii++)
164 : {
165 72 : apath = &mp->mr_route.mr_paths[ii];
166 72 : rpath = &rpaths[ii];
167 :
168 72 : rv = fib_api_path_decode (apath, rpath);
169 :
170 72 : if (0 != rv)
171 0 : goto out;
172 : }
173 :
174 66 : rv = fib_api_route_add_del (
175 66 : mp->mr_is_add, mp->mr_is_multipath, fib_index, &pfx, FIB_SOURCE_API,
176 66 : (mp->mr_route.mr_is_multicast ? FIB_ENTRY_FLAG_MULTICAST :
177 : FIB_ENTRY_FLAG_NONE),
178 : rpaths);
179 :
180 66 : if (mp->mr_is_add && 0 == rv)
181 33 : *stats_index = fib_table_entry_get_stats_index (fib_index, &pfx);
182 :
183 33 : out:
184 66 : vec_free (rpaths);
185 :
186 66 : return (rv);
187 : }
188 :
189 : void
190 66 : vl_api_mpls_route_add_del_t_handler (vl_api_mpls_route_add_del_t * mp)
191 : {
192 : vl_api_mpls_route_add_del_reply_t *rmp;
193 : vnet_main_t *vnm;
194 : u32 stats_index;
195 : int rv;
196 :
197 66 : vnm = vnet_get_main ();
198 66 : stats_index = ~0;
199 :
200 66 : rv = mpls_route_add_del_t_handler (vnm, mp, &stats_index);
201 :
202 : /* *INDENT-OFF* */
203 66 : REPLY_MACRO2 (VL_API_MPLS_ROUTE_ADD_DEL_REPLY,
204 : ({
205 : rmp->stats_index = htonl (stats_index);
206 : }));
207 : /* *INDENT-ON* */
208 : }
209 :
210 : void
211 44 : mpls_table_create (u32 table_id, u8 is_api, const u8 * name)
212 : {
213 : /*
214 : * The MPLS defult table must also be explicitly created via the API.
215 : * So in contrast to IP, it gets no special treatment here.
216 : */
217 :
218 : /*
219 : * The API holds only one lock on the table.
220 : * i.e. it can be added many times via the API but needs to be
221 : * deleted only once.
222 : */
223 44 : fib_table_find_or_create_and_lock_w_name (FIB_PROTOCOL_MPLS,
224 : table_id,
225 : (is_api ?
226 : FIB_SOURCE_API :
227 : FIB_SOURCE_CLI), name);
228 44 : }
229 :
230 : static void
231 418 : vl_api_mpls_tunnel_add_del_t_handler (vl_api_mpls_tunnel_add_del_t * mp)
232 : {
233 418 : u32 tunnel_sw_if_index = ~0, tunnel_index = ~0;
234 : vl_api_mpls_tunnel_add_del_reply_t *rmp;
235 418 : fib_route_path_t *rpath, *rpaths = NULL;
236 418 : int ii, rv = 0;
237 :
238 418 : vec_validate (rpaths, mp->mt_tunnel.mt_n_paths - 1);
239 :
240 838 : for (ii = 0; ii < mp->mt_tunnel.mt_n_paths; ii++)
241 : {
242 420 : rpath = &rpaths[ii];
243 :
244 420 : rv = fib_api_path_decode (&mp->mt_tunnel.mt_paths[ii], rpath);
245 :
246 420 : if (0 != rv)
247 0 : goto out;
248 : }
249 418 : tunnel_sw_if_index = ntohl (mp->mt_tunnel.mt_sw_if_index);
250 :
251 418 : if (mp->mt_is_add)
252 : {
253 209 : if (~0 == tunnel_sw_if_index)
254 : tunnel_sw_if_index =
255 209 : vnet_mpls_tunnel_create (mp->mt_tunnel.mt_l2_only,
256 209 : mp->mt_tunnel.mt_is_multicast,
257 209 : mp->mt_tunnel.mt_tag);
258 209 : vnet_mpls_tunnel_path_add (tunnel_sw_if_index, rpaths);
259 :
260 209 : tunnel_index = vnet_mpls_tunnel_get_index (tunnel_sw_if_index);
261 : }
262 : else
263 : {
264 209 : tunnel_index = vnet_mpls_tunnel_get_index (tunnel_sw_if_index);
265 209 : tunnel_sw_if_index = ntohl (mp->mt_tunnel.mt_sw_if_index);
266 209 : if (!vnet_mpls_tunnel_path_remove (tunnel_sw_if_index, rpaths))
267 209 : vnet_mpls_tunnel_del (tunnel_sw_if_index);
268 : }
269 :
270 418 : vec_free (rpaths);
271 :
272 418 : out:
273 : /* *INDENT-OFF* */
274 418 : REPLY_MACRO2(VL_API_MPLS_TUNNEL_ADD_DEL_REPLY,
275 : ({
276 : rmp->sw_if_index = ntohl(tunnel_sw_if_index);
277 : rmp->tunnel_index = ntohl(tunnel_index);
278 : }));
279 : /* *INDENT-ON* */
280 : }
281 :
282 : static void
283 270 : vl_api_sw_interface_set_mpls_enable_t_handler
284 : (vl_api_sw_interface_set_mpls_enable_t * mp)
285 : {
286 : vl_api_sw_interface_set_mpls_enable_reply_t *rmp;
287 270 : int rv = 0;
288 :
289 270 : VALIDATE_SW_IF_INDEX (mp);
290 :
291 270 : rv = mpls_sw_interface_enable_disable (&mpls_main, ntohl (mp->sw_if_index),
292 270 : mp->enable);
293 :
294 270 : BAD_SW_IF_INDEX_LABEL;
295 270 : REPLY_MACRO (VL_API_SW_INTERFACE_SET_MPLS_ENABLE_REPLY);
296 : }
297 :
298 : typedef struct mpls_tunnel_send_walk_ctx_t_
299 : {
300 : vl_api_registration_t *reg;
301 : u32 sw_if_index;
302 : u32 context;
303 : } mpls_tunnel_send_walk_ctx_t;
304 :
305 : static void
306 40009 : send_mpls_tunnel_entry (u32 mti, void *arg)
307 : {
308 : mpls_tunnel_send_walk_ctx_t *ctx;
309 : vl_api_mpls_tunnel_details_t *mp;
310 40009 : fib_path_encode_ctx_t path_ctx = {
311 : .rpaths = NULL,
312 : };
313 : const mpls_tunnel_t *mt;
314 : fib_route_path_t *rpath;
315 : vl_api_fib_path_t *fp;
316 : u32 n;
317 :
318 40009 : ctx = arg;
319 :
320 40009 : mt = mpls_tunnel_get (mti);
321 :
322 40009 : if (~0 != ctx->sw_if_index && mt->mt_sw_if_index != ctx->sw_if_index)
323 0 : return;
324 :
325 40009 : n = fib_path_list_get_n_paths (mt->mt_path_list);
326 :
327 40009 : mp = vl_msg_api_alloc (sizeof (*mp) + n * sizeof (vl_api_fib_path_t));
328 40009 : clib_memset (mp, 0, sizeof (*mp) + n * sizeof (vl_api_fib_path_t));
329 :
330 40009 : mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_MPLS_TUNNEL_DETAILS);
331 40009 : mp->context = ctx->context;
332 :
333 40009 : mp->mt_tunnel.mt_n_paths = n;
334 40009 : mp->mt_tunnel.mt_sw_if_index = ntohl (mt->mt_sw_if_index);
335 40009 : mp->mt_tunnel.mt_tunnel_index = ntohl (mti);
336 40009 : mp->mt_tunnel.mt_l2_only = ! !(MPLS_TUNNEL_FLAG_L2 & mt->mt_flags);
337 40009 : mp->mt_tunnel.mt_is_multicast = ! !(MPLS_TUNNEL_FLAG_MCAST & mt->mt_flags);
338 40009 : memcpy (mp->mt_tunnel.mt_tag, mt->mt_tag, sizeof (mp->mt_tunnel.mt_tag));
339 :
340 40009 : fib_path_list_walk_w_ext (mt->mt_path_list,
341 : &mt->mt_path_exts, fib_path_encode, &path_ctx);
342 :
343 40009 : fp = mp->mt_tunnel.mt_paths;
344 80019 : vec_foreach (rpath, path_ctx.rpaths)
345 : {
346 40010 : fib_api_path_encode (rpath, fp);
347 40010 : fp++;
348 : }
349 :
350 40009 : vl_api_send_msg (ctx->reg, (u8 *) mp);
351 :
352 40009 : vec_free (path_ctx.rpaths);
353 : }
354 :
355 : static void
356 416 : vl_api_mpls_tunnel_dump_t_handler (vl_api_mpls_tunnel_dump_t * mp)
357 : {
358 : vl_api_registration_t *reg;
359 :
360 416 : reg = vl_api_client_index_to_registration (mp->client_index);
361 416 : if (!reg)
362 0 : return;
363 :
364 416 : mpls_tunnel_send_walk_ctx_t ctx = {
365 : .reg = reg,
366 416 : .sw_if_index = ntohl (mp->sw_if_index),
367 416 : .context = mp->context,
368 : };
369 416 : mpls_tunnel_walk (send_mpls_tunnel_entry, &ctx);
370 : }
371 :
372 : static void
373 41 : send_mpls_table_details (vpe_api_main_t * am,
374 : vl_api_registration_t * reg,
375 : u32 context, const fib_table_t * table)
376 : {
377 : vl_api_mpls_table_details_t *mp;
378 :
379 41 : mp = vl_msg_api_alloc (sizeof (*mp));
380 41 : memset (mp, 0, sizeof (*mp));
381 41 : mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_MPLS_TABLE_DETAILS);
382 41 : mp->context = context;
383 :
384 41 : mp->mt_table.mt_table_id = htonl (table->ft_table_id);
385 41 : memcpy (mp->mt_table.mt_name,
386 41 : table->ft_desc,
387 41 : clib_min (vec_len (table->ft_desc), sizeof (mp->mt_table.mt_name)));
388 :
389 41 : vl_api_send_msg (reg, (u8 *) mp);
390 41 : }
391 :
392 : static void
393 82 : vl_api_mpls_table_dump_t_handler (vl_api_mpls_table_dump_t * mp)
394 : {
395 82 : vpe_api_main_t *am = &vpe_api_main;
396 : vl_api_registration_t *reg;
397 82 : mpls_main_t *mm = &mpls_main;
398 : fib_table_t *fib_table;
399 :
400 82 : reg = vl_api_client_index_to_registration (mp->client_index);
401 82 : if (!reg)
402 0 : return;
403 :
404 : /* *INDENT-OFF* */
405 123 : pool_foreach (fib_table, mm->fibs)
406 : {
407 41 : send_mpls_table_details(am, reg, mp->context, fib_table);
408 : }
409 : /* *INDENT-ON* */
410 : }
411 :
412 : static void
413 0 : send_mpls_interface_details (vpe_api_main_t *am, vl_api_registration_t *reg,
414 : u32 context, const u32 sw_if_index)
415 : {
416 : vl_api_mpls_interface_details_t *mp;
417 :
418 0 : mp = vl_msg_api_alloc_zero (sizeof (*mp));
419 0 : mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_MPLS_INTERFACE_DETAILS);
420 0 : mp->context = context;
421 :
422 0 : mp->sw_if_index = htonl (sw_if_index);
423 0 : vl_api_send_msg (reg, (u8 *) mp);
424 0 : }
425 :
426 : static void
427 0 : vl_api_mpls_interface_dump_t_handler (vl_api_mpls_interface_dump_t *mp)
428 : {
429 0 : vpe_api_main_t *am = &vpe_api_main;
430 : vl_api_registration_t *reg;
431 0 : vnet_interface_main_t *im = &vnet_main.interface_main;
432 : vnet_sw_interface_t *si;
433 0 : u32 sw_if_index = ~0;
434 :
435 0 : reg = vl_api_client_index_to_registration (mp->client_index);
436 0 : if (!reg)
437 0 : return;
438 0 : sw_if_index = ntohl (mp->sw_if_index);
439 :
440 0 : if (sw_if_index == ~0)
441 : {
442 0 : pool_foreach (si, im->sw_interfaces)
443 : {
444 0 : if (mpls_sw_interface_is_enabled (si->sw_if_index))
445 : {
446 0 : send_mpls_interface_details (am, reg, mp->context,
447 : si->sw_if_index);
448 : }
449 : }
450 : }
451 : else
452 : {
453 0 : if (mpls_sw_interface_is_enabled (sw_if_index))
454 : {
455 0 : send_mpls_interface_details (am, reg, mp->context, sw_if_index);
456 : }
457 : }
458 : }
459 :
460 : static void
461 20057 : send_mpls_route_details (vpe_api_main_t * am,
462 : vl_api_registration_t * reg,
463 : u32 context, fib_node_index_t fib_entry_index)
464 : {
465 : fib_route_path_t *rpaths, *rpath;
466 : vl_api_mpls_route_details_t *mp;
467 : const fib_prefix_t *pfx;
468 : vl_api_fib_path_t *fp;
469 : int path_count;
470 :
471 20057 : rpaths = fib_entry_encode (fib_entry_index);
472 20057 : pfx = fib_entry_get_prefix (fib_entry_index);
473 :
474 20057 : path_count = vec_len (rpaths);
475 20057 : mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
476 20057 : if (!mp)
477 0 : return;
478 20057 : clib_memset (mp, 0, sizeof (*mp));
479 20057 : mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_MPLS_ROUTE_DETAILS);
480 20057 : mp->context = context;
481 :
482 20057 : mp->mr_route.mr_table_id =
483 20057 : htonl (fib_table_get_table_id
484 20057 : (fib_entry_get_fib_index (fib_entry_index), pfx->fp_proto));
485 20057 : mp->mr_route.mr_eos = pfx->fp_eos;
486 20057 : mp->mr_route.mr_eos_proto = pfx->fp_payload_proto;
487 20057 : mp->mr_route.mr_label = htonl (pfx->fp_label);
488 :
489 20057 : mp->mr_route.mr_n_paths = path_count;
490 20057 : fp = mp->mr_route.mr_paths;
491 40117 : vec_foreach (rpath, rpaths)
492 : {
493 20060 : fib_api_path_encode (rpath, fp);
494 20060 : fp++;
495 : }
496 :
497 20057 : vec_free (rpaths);
498 20057 : vl_api_send_msg (reg, (u8 *) mp);
499 : }
500 :
501 : typedef struct vl_api_mpls_route_dump_table_walk_ctx_t_
502 : {
503 : fib_node_index_t *lfeis;
504 : } vl_api_mpls_route_dump_table_walk_ctx_t;
505 :
506 : static fib_table_walk_rc_t
507 20057 : vl_api_mpls_route_dump_table_walk (fib_node_index_t fei, void *arg)
508 : {
509 20057 : vl_api_mpls_route_dump_table_walk_ctx_t *ctx = arg;
510 :
511 20057 : vec_add1 (ctx->lfeis, fei);
512 :
513 20057 : return (FIB_TABLE_WALK_CONTINUE);
514 : }
515 :
516 : static void
517 335 : vl_api_mpls_route_dump_t_handler (vl_api_mpls_route_dump_t * mp)
518 : {
519 335 : vpe_api_main_t *am = &vpe_api_main;
520 : vl_api_registration_t *reg;
521 335 : fib_node_index_t *lfeip = NULL;
522 335 : vl_api_mpls_route_dump_table_walk_ctx_t ctx = {
523 : .lfeis = NULL,
524 : };
525 : u32 fib_index;
526 :
527 335 : reg = vl_api_client_index_to_registration (mp->client_index);
528 335 : if (!reg)
529 0 : return;
530 :
531 335 : fib_index = fib_table_find (FIB_PROTOCOL_MPLS,
532 : ntohl (mp->table.mt_table_id));
533 :
534 335 : if (INDEX_INVALID != fib_index)
535 : {
536 335 : fib_table_walk (fib_index,
537 : FIB_PROTOCOL_MPLS,
538 : vl_api_mpls_route_dump_table_walk, &ctx);
539 335 : vec_sort_with_function (ctx.lfeis, fib_entry_cmp_for_sort);
540 :
541 20392 : vec_foreach (lfeip, ctx.lfeis)
542 : {
543 20057 : send_mpls_route_details (am, reg, mp->context, *lfeip);
544 : }
545 :
546 335 : vec_free (ctx.lfeis);
547 : }
548 : }
549 :
550 : #include <vnet/mpls/mpls.api.c>
551 : static clib_error_t *
552 575 : mpls_api_hookup (vlib_main_t * vm)
553 : {
554 575 : api_main_t *am = vlibapi_get_main ();
555 :
556 : /*
557 : * Trace space for 8 MPLS encap labels
558 : */
559 575 : vl_api_increase_msg_trace_size (am, VL_API_MPLS_TUNNEL_ADD_DEL,
560 : 8 * sizeof (u32));
561 :
562 : /*
563 : * Set up the (msg_name, crc, message-id) table
564 : */
565 575 : REPLY_MSG_ID_BASE = setup_message_id_table ();
566 :
567 575 : return 0;
568 : }
569 :
570 10367 : VLIB_API_INIT_FUNCTION (mpls_api_hookup);
571 :
572 : /*
573 : * fd.io coding-style-patch-verification: ON
574 : *
575 : * Local Variables:
576 : * eval: (c-set-style "gnu")
577 : * End:
578 : */
|