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 20057 : send_mpls_route_details (vpe_api_main_t * am,
414 : vl_api_registration_t * reg,
415 : u32 context, fib_node_index_t fib_entry_index)
416 : {
417 : fib_route_path_t *rpaths, *rpath;
418 : vl_api_mpls_route_details_t *mp;
419 : const fib_prefix_t *pfx;
420 : vl_api_fib_path_t *fp;
421 : int path_count;
422 :
423 20057 : rpaths = fib_entry_encode (fib_entry_index);
424 20057 : pfx = fib_entry_get_prefix (fib_entry_index);
425 :
426 20057 : path_count = vec_len (rpaths);
427 20057 : mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
428 20057 : if (!mp)
429 0 : return;
430 20057 : clib_memset (mp, 0, sizeof (*mp));
431 20057 : mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_MPLS_ROUTE_DETAILS);
432 20057 : mp->context = context;
433 :
434 20057 : mp->mr_route.mr_table_id =
435 20057 : htonl (fib_table_get_table_id
436 20057 : (fib_entry_get_fib_index (fib_entry_index), pfx->fp_proto));
437 20057 : mp->mr_route.mr_eos = pfx->fp_eos;
438 20057 : mp->mr_route.mr_eos_proto = pfx->fp_payload_proto;
439 20057 : mp->mr_route.mr_label = htonl (pfx->fp_label);
440 :
441 20057 : mp->mr_route.mr_n_paths = path_count;
442 20057 : fp = mp->mr_route.mr_paths;
443 40117 : vec_foreach (rpath, rpaths)
444 : {
445 20060 : fib_api_path_encode (rpath, fp);
446 20060 : fp++;
447 : }
448 :
449 20057 : vec_free (rpaths);
450 20057 : vl_api_send_msg (reg, (u8 *) mp);
451 : }
452 :
453 : typedef struct vl_api_mpls_route_dump_table_walk_ctx_t_
454 : {
455 : fib_node_index_t *lfeis;
456 : } vl_api_mpls_route_dump_table_walk_ctx_t;
457 :
458 : static fib_table_walk_rc_t
459 20057 : vl_api_mpls_route_dump_table_walk (fib_node_index_t fei, void *arg)
460 : {
461 20057 : vl_api_mpls_route_dump_table_walk_ctx_t *ctx = arg;
462 :
463 20057 : vec_add1 (ctx->lfeis, fei);
464 :
465 20057 : return (FIB_TABLE_WALK_CONTINUE);
466 : }
467 :
468 : static void
469 335 : vl_api_mpls_route_dump_t_handler (vl_api_mpls_route_dump_t * mp)
470 : {
471 335 : vpe_api_main_t *am = &vpe_api_main;
472 : vl_api_registration_t *reg;
473 335 : fib_node_index_t *lfeip = NULL;
474 335 : vl_api_mpls_route_dump_table_walk_ctx_t ctx = {
475 : .lfeis = NULL,
476 : };
477 : u32 fib_index;
478 :
479 335 : reg = vl_api_client_index_to_registration (mp->client_index);
480 335 : if (!reg)
481 0 : return;
482 :
483 335 : fib_index = fib_table_find (FIB_PROTOCOL_MPLS,
484 : ntohl (mp->table.mt_table_id));
485 :
486 335 : if (INDEX_INVALID != fib_index)
487 : {
488 335 : fib_table_walk (fib_index,
489 : FIB_PROTOCOL_MPLS,
490 : vl_api_mpls_route_dump_table_walk, &ctx);
491 335 : vec_sort_with_function (ctx.lfeis, fib_entry_cmp_for_sort);
492 :
493 20392 : vec_foreach (lfeip, ctx.lfeis)
494 : {
495 20057 : send_mpls_route_details (am, reg, mp->context, *lfeip);
496 : }
497 :
498 335 : vec_free (ctx.lfeis);
499 : }
500 : }
501 :
502 : #include <vnet/mpls/mpls.api.c>
503 : static clib_error_t *
504 559 : mpls_api_hookup (vlib_main_t * vm)
505 : {
506 559 : api_main_t *am = vlibapi_get_main ();
507 :
508 : /*
509 : * Trace space for 8 MPLS encap labels
510 : */
511 559 : vl_api_increase_msg_trace_size (am, VL_API_MPLS_TUNNEL_ADD_DEL,
512 : 8 * sizeof (u32));
513 :
514 : /*
515 : * Set up the (msg_name, crc, message-id) table
516 : */
517 559 : REPLY_MSG_ID_BASE = setup_message_id_table ();
518 :
519 559 : return 0;
520 : }
521 :
522 10079 : VLIB_API_INIT_FUNCTION (mpls_api_hookup);
523 :
524 : /*
525 : * fd.io coding-style-patch-verification: ON
526 : *
527 : * Local Variables:
528 : * eval: (c-set-style "gnu")
529 : * End:
530 : */
|