Line data Source code
1 : /*
2 : * mpls.c: mpls
3 : *
4 : * Copyright (c) 2012 Cisco and/or its affiliates.
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <vnet/vnet.h>
19 : #include <vnet/mpls/mpls.h>
20 : #include <vnet/fib/ip4_fib.h>
21 : #include <vnet/fib/mpls_fib.h>
22 :
23 : const static char* mpls_eos_bit_names[] = MPLS_EOS_BITS;
24 :
25 : mpls_main_t mpls_main;
26 :
27 13097 : u8 * format_mpls_unicast_label (u8 * s, va_list * args)
28 : {
29 13097 : mpls_label_t label = va_arg (*args, mpls_label_t);
30 :
31 13097 : switch (label) {
32 0 : case MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL:
33 0 : s = format (s, "%s", MPLS_IETF_IPV4_EXPLICIT_NULL_STRING);
34 0 : break;
35 0 : case MPLS_IETF_ROUTER_ALERT_LABEL:
36 0 : s = format (s, "%s", MPLS_IETF_ROUTER_ALERT_STRING);
37 0 : break;
38 0 : case MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL:
39 0 : s = format (s, "%s", MPLS_IETF_IPV6_EXPLICIT_NULL_STRING);
40 0 : break;
41 0 : case MPLS_IETF_IMPLICIT_NULL_LABEL:
42 0 : s = format (s, "%s", MPLS_IETF_IMPLICIT_NULL_STRING);
43 0 : break;
44 0 : case MPLS_IETF_ELI_LABEL:
45 0 : s = format (s, "%s", MPLS_IETF_ELI_STRING);
46 0 : break;
47 0 : case MPLS_IETF_GAL_LABEL:
48 0 : s = format (s, "%s", MPLS_IETF_GAL_STRING);
49 0 : break;
50 0 : case MPLS_LABEL_POP:
51 0 : s = format (s, "pop");
52 0 : break;
53 13097 : default:
54 13097 : s = format (s, "%d", label);
55 13097 : break;
56 : }
57 13097 : return s;
58 : }
59 :
60 0 : uword unformat_mpls_unicast_label (unformat_input_t * input, va_list * args)
61 : {
62 0 : mpls_label_t *label = va_arg (*args, mpls_label_t*);
63 :
64 0 : if (unformat (input, MPLS_IETF_IPV4_EXPLICIT_NULL_STRING))
65 0 : *label = MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL;
66 0 : else if (unformat (input, MPLS_IETF_IPV6_EXPLICIT_NULL_STRING))
67 0 : *label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL;
68 0 : else if (unformat (input, MPLS_IETF_ROUTER_ALERT_STRING))
69 0 : *label = MPLS_IETF_ROUTER_ALERT_LABEL;
70 0 : else if (unformat (input, MPLS_IETF_IMPLICIT_NULL_STRING))
71 0 : *label = MPLS_IETF_IMPLICIT_NULL_LABEL;
72 0 : else if (unformat (input, MPLS_IETF_IPV4_EXPLICIT_NULL_BRIEF_STRING))
73 0 : *label = MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL;
74 0 : else if (unformat (input, MPLS_IETF_IPV6_EXPLICIT_NULL_BRIEF_STRING))
75 0 : *label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL;
76 0 : else if (unformat (input, MPLS_IETF_ROUTER_ALERT_BRIEF_STRING))
77 0 : *label = MPLS_IETF_ROUTER_ALERT_LABEL;
78 0 : else if (unformat (input, MPLS_IETF_IMPLICIT_NULL_BRIEF_STRING))
79 0 : *label = MPLS_IETF_IMPLICIT_NULL_LABEL;
80 0 : else if (unformat (input, "%d", label))
81 : ;
82 : else
83 0 : return (0);
84 :
85 0 : return (1);
86 : }
87 :
88 13093 : u8 * format_mpls_eos_bit (u8 * s, va_list * args)
89 : {
90 13093 : mpls_eos_bit_t eb = va_arg (*args, mpls_eos_bit_t);
91 :
92 13093 : ASSERT(eb <= MPLS_EOS);
93 :
94 13093 : s = format(s, "%s", mpls_eos_bit_names[eb]);
95 :
96 13093 : return (s);
97 : }
98 :
99 13089 : u8 * format_mpls_header (u8 * s, va_list * args)
100 : {
101 13089 : mpls_unicast_header_t hdr = va_arg (*args, mpls_unicast_header_t);
102 :
103 13089 : return (format(s, "[%U:%d:%d:%U]",
104 : format_mpls_unicast_label,
105 : vnet_mpls_uc_get_label(hdr.label_exp_s_ttl),
106 : vnet_mpls_uc_get_ttl(hdr.label_exp_s_ttl),
107 : vnet_mpls_uc_get_exp(hdr.label_exp_s_ttl),
108 : format_mpls_eos_bit,
109 : vnet_mpls_uc_get_s(hdr.label_exp_s_ttl)));
110 : }
111 :
112 : uword
113 0 : unformat_mpls_header (unformat_input_t * input, va_list * args)
114 : {
115 0 : u8 ** result = va_arg (*args, u8 **);
116 0 : mpls_unicast_header_t _h, * h = &_h;
117 : u32 label, label_exp_s_ttl;
118 :
119 0 : if (! unformat (input, "MPLS %d", &label))
120 0 : return 0;
121 :
122 0 : label_exp_s_ttl = (label<<12) | (1<<8) /* s-bit */ | 0xFF;
123 0 : h->label_exp_s_ttl = clib_host_to_net_u32 (label_exp_s_ttl);
124 :
125 : /* Add gre, mpls headers to result. */
126 : {
127 : void * p;
128 0 : u32 h_n_bytes = sizeof (h[0]);
129 :
130 0 : vec_add2 (*result, p, h_n_bytes);
131 0 : clib_memcpy (p, h, h_n_bytes);
132 : }
133 :
134 0 : return 1;
135 : }
136 :
137 : uword
138 0 : unformat_mpls_label_net_byte_order (unformat_input_t * input,
139 : va_list * args)
140 : {
141 0 : u32 * result = va_arg (*args, u32 *);
142 : u32 label;
143 :
144 0 : if (!unformat (input, "MPLS: label %d", &label))
145 0 : return 0;
146 :
147 0 : label = (label<<12) | (1<<8) /* s-bit set */ | 0xFF /* ttl */;
148 :
149 0 : *result = clib_host_to_net_u32 (label);
150 0 : return 1;
151 : }
152 :
153 10740 : u8 * format_mpls_unicast_header_host_byte_order (u8 * s, va_list * args)
154 : {
155 10740 : mpls_unicast_header_t *h = va_arg(*args, mpls_unicast_header_t *);
156 10740 : u32 label = h->label_exp_s_ttl;
157 :
158 10740 : s = format (s, "label %d exp %d, s %d, ttl %d",
159 : vnet_mpls_uc_get_label (label),
160 : vnet_mpls_uc_get_exp (label),
161 : vnet_mpls_uc_get_s (label),
162 : vnet_mpls_uc_get_ttl (label));
163 10740 : return s;
164 : }
165 :
166 10740 : u8 * format_mpls_unicast_header_net_byte_order (u8 * s, va_list * args)
167 : {
168 10740 : mpls_unicast_header_t *h = va_arg(*args, mpls_unicast_header_t *);
169 : mpls_unicast_header_t h_host;
170 :
171 10740 : h_host.label_exp_s_ttl = clib_net_to_host_u32 (h->label_exp_s_ttl);
172 :
173 10740 : return format (s, "%U", format_mpls_unicast_header_host_byte_order,
174 : &h_host);
175 : }
176 :
177 : typedef struct {
178 : u32 fib_index;
179 : u32 entry_index;
180 : u32 dest;
181 : u32 s_bit;
182 : u32 label;
183 : } show_mpls_fib_t;
184 :
185 : int
186 0 : mpls_dest_cmp(void * a1, void * a2)
187 : {
188 0 : show_mpls_fib_t * r1 = a1;
189 0 : show_mpls_fib_t * r2 = a2;
190 :
191 0 : return clib_net_to_host_u32(r1->dest) - clib_net_to_host_u32(r2->dest);
192 : }
193 :
194 : int
195 0 : mpls_fib_index_cmp(void * a1, void * a2)
196 : {
197 0 : show_mpls_fib_t * r1 = a1;
198 0 : show_mpls_fib_t * r2 = a2;
199 :
200 0 : return r1->fib_index - r2->fib_index;
201 : }
202 :
203 : int
204 0 : mpls_label_cmp(void * a1, void * a2)
205 : {
206 0 : show_mpls_fib_t * r1 = a1;
207 0 : show_mpls_fib_t * r2 = a2;
208 :
209 0 : return r1->label - r2->label;
210 : }
211 :
212 : static clib_error_t *
213 0 : vnet_mpls_local_label (vlib_main_t * vm,
214 : unformat_input_t * input,
215 : vlib_cli_command_t * cmd)
216 : {
217 0 : unformat_input_t _line_input, * line_input = &_line_input;
218 : u32 table_id, is_del, is_ip, payload_proto;
219 0 : fib_route_path_t *rpaths = NULL, rpath;
220 : mpls_label_t local_label;
221 : clib_error_t * error;
222 : mpls_eos_bit_t eos;
223 : fib_prefix_t pfx;
224 :
225 0 : error = NULL;
226 0 : is_ip = 0;
227 0 : table_id = 0;
228 0 : eos = MPLS_EOS;
229 0 : is_del = 0;
230 0 : local_label = MPLS_LABEL_INVALID;
231 0 : clib_memset(&pfx, 0, sizeof(pfx));
232 0 : payload_proto = DPO_PROTO_MPLS;
233 :
234 : /* Get a line of input. */
235 0 : if (! unformat_user (input, unformat_line_input, line_input))
236 0 : return 0;
237 :
238 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
239 : {
240 0 : if (unformat (line_input, "table %d", &table_id))
241 : ;
242 0 : else if (unformat (line_input, "del"))
243 0 : is_del = 1;
244 0 : else if (unformat (line_input, "add"))
245 0 : is_del = 0;
246 0 : else if (unformat (line_input, "eos"))
247 0 : pfx.fp_eos = MPLS_EOS;
248 0 : else if (unformat (line_input, "non-eos"))
249 0 : pfx.fp_eos = MPLS_NON_EOS;
250 0 : else if (unformat (line_input, "%U/%d",
251 : unformat_ip4_address,
252 : &pfx.fp_addr.ip4,
253 : &pfx.fp_len))
254 : {
255 0 : pfx.fp_proto = FIB_PROTOCOL_IP4;
256 0 : is_ip = 1;
257 : }
258 0 : else if (unformat (line_input, "%U/%d",
259 : unformat_ip6_address,
260 : &pfx.fp_addr.ip6,
261 : &pfx.fp_len))
262 : {
263 0 : pfx.fp_proto = FIB_PROTOCOL_IP6;
264 0 : is_ip = 1;
265 : }
266 0 : else if (unformat (line_input, "via %U",
267 : unformat_fib_route_path,
268 : &rpath, &payload_proto))
269 : {
270 0 : pfx.fp_payload_proto = payload_proto;
271 0 : vec_add1(rpaths, rpath);
272 : }
273 0 : else if (unformat (line_input, "%d", &local_label))
274 : ;
275 : else
276 : {
277 0 : error = clib_error_return (0, "unknown input: %U",
278 : format_unformat_error, line_input);
279 0 : goto done;
280 : }
281 :
282 : }
283 :
284 0 : if (MPLS_LABEL_INVALID == local_label)
285 : {
286 0 : error = clib_error_return (0, "local-label required: %U",
287 : format_unformat_error, input);
288 0 : goto done;
289 : }
290 :
291 :
292 0 : if (is_ip)
293 : {
294 0 : u32 fib_index = fib_table_find(pfx.fp_proto, table_id);
295 :
296 0 : if (FIB_NODE_INDEX_INVALID == fib_index)
297 : {
298 0 : error = clib_error_return (0, "%U table-id %d does not exist",
299 : format_fib_protocol, pfx.fp_proto, table_id);
300 0 : goto done;
301 : }
302 :
303 0 : if (is_del)
304 : {
305 0 : fib_table_entry_local_label_remove(fib_index, &pfx, local_label);
306 : }
307 : else
308 : {
309 0 : fib_table_entry_local_label_add(fib_index, &pfx, local_label);
310 : }
311 : }
312 : else
313 : {
314 : fib_node_index_t fib_index;
315 :
316 0 : if (NULL == rpaths)
317 : {
318 0 : error = clib_error_return(0 , "no paths");
319 0 : goto done;
320 : }
321 :
322 0 : pfx.fp_proto = FIB_PROTOCOL_MPLS;
323 0 : pfx.fp_len = 21;
324 0 : pfx.fp_label = local_label;
325 0 : pfx.fp_payload_proto = rpaths[0].frp_proto;
326 :
327 0 : fib_index = mpls_fib_index_from_table_id(table_id);
328 :
329 0 : if (FIB_NODE_INDEX_INVALID == fib_index)
330 : {
331 0 : error = clib_error_return (0, "MPLS table-id %d does not exist",
332 : table_id);
333 0 : goto done;
334 : }
335 :
336 0 : if (is_del)
337 : {
338 0 : fib_table_entry_path_remove2(fib_index,
339 : &pfx,
340 : FIB_SOURCE_CLI,
341 : rpaths);
342 : }
343 : else
344 : {
345 : fib_node_index_t lfe;
346 :
347 0 : lfe = fib_table_entry_path_add2(fib_index,
348 : &pfx,
349 : FIB_SOURCE_CLI,
350 : FIB_ENTRY_FLAG_NONE,
351 : rpaths);
352 :
353 0 : if (FIB_NODE_INDEX_INVALID == lfe)
354 : {
355 0 : error = clib_error_return (0, "Failed to create %U-%U in MPLS table-id %d",
356 : format_mpls_unicast_label, local_label,
357 : format_mpls_eos_bit, eos,
358 : table_id);
359 0 : goto done;
360 : }
361 : }
362 : }
363 :
364 0 : done:
365 0 : unformat_free (line_input);
366 :
367 0 : return error;
368 : }
369 :
370 285289 : VLIB_CLI_COMMAND (mpls_local_label_command, static) = {
371 : .path = "mpls local-label",
372 : .function = vnet_mpls_local_label,
373 : .short_help = "mpls local-label [add|del] <label-value> [eos|non-eos] via [next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-attached] [rx-ip4 <interface>] [out-labels <value value value>]",
374 : };
375 :
376 : clib_error_t *
377 0 : vnet_mpls_table_cmd (vlib_main_t * vm,
378 : unformat_input_t * main_input,
379 : vlib_cli_command_t * cmdo)
380 : {
381 0 : unformat_input_t _line_input, *line_input = &_line_input;
382 0 : clib_error_t *error = NULL;
383 : u32 table_id, is_add;
384 0 : u8 *name = NULL;
385 :
386 0 : is_add = 1;
387 0 : table_id = ~0;
388 :
389 : /* Get a line of input. */
390 0 : if (!unformat_user (main_input, unformat_line_input, line_input))
391 0 : return 0;
392 :
393 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
394 : {
395 0 : if (unformat (line_input, "%d", &table_id))
396 : ;
397 0 : else if (unformat (line_input, "del"))
398 0 : is_add = 0;
399 0 : else if (unformat (line_input, "add"))
400 0 : is_add = 1;
401 0 : else if (unformat (line_input, "name %s", &name))
402 : ;
403 : else
404 : {
405 0 : error = unformat_parse_error (line_input);
406 0 : goto done;
407 : }
408 : }
409 :
410 0 : if (~0 == table_id)
411 : {
412 0 : error = clib_error_return (0, "No table id");
413 0 : goto done;
414 : }
415 : else
416 : {
417 0 : if (is_add)
418 : {
419 0 : mpls_table_create (table_id, 0, name);
420 : }
421 : else
422 : {
423 0 : mpls_table_delete (table_id, 0);
424 : }
425 : }
426 :
427 0 : done:
428 0 : vec_free (name);
429 0 : unformat_free (line_input);
430 0 : return error;
431 : }
432 :
433 : /* *INDENT-ON* */
434 : /*?
435 : * This command is used to add or delete MPLS Tables. All
436 : * Tables must be explicitly added before that can be used,
437 : * Including the default table.
438 : ?*/
439 : /* *INDENT-OFF* */
440 285289 : VLIB_CLI_COMMAND (mpls_table_command, static) = {
441 : .path = "mpls table",
442 : .short_help = "mpls table [add|del] <table-id>",
443 : .function = vnet_mpls_table_cmd,
444 : .is_mp_safe = 1,
445 : };
446 :
447 : static clib_error_t *
448 575 : mpls_init (vlib_main_t * vm)
449 : {
450 : clib_error_t * error;
451 :
452 575 : if ((error = vlib_call_init_function (vm, ip_main_init)))
453 0 : return error;
454 :
455 575 : return vlib_call_init_function (vm, mpls_input_init);
456 : }
457 :
458 14399 : VLIB_INIT_FUNCTION (mpls_init);
|