dpdk: Add support for Mellanox ConnectX-4 devices
[vpp.git] / src / vnet / mpls / mpls.c
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 u8 * format_mpls_unicast_label (u8 * s, va_list * args)
28 {
29   mpls_label_t label = va_arg (*args, mpls_label_t);
30
31   switch (label) {
32   case MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL:
33       s = format (s, "%s", MPLS_IETF_IPV4_EXPLICIT_NULL_STRING);
34       break;
35   case MPLS_IETF_ROUTER_ALERT_LABEL:
36       s = format (s, "%s", MPLS_IETF_ROUTER_ALERT_STRING);
37       break;
38   case MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL:
39       s = format (s, "%s", MPLS_IETF_IPV6_EXPLICIT_NULL_STRING);
40       break;
41   case MPLS_IETF_IMPLICIT_NULL_LABEL:
42       s = format (s, "%s", MPLS_IETF_IMPLICIT_NULL_STRING);
43       break;
44   case MPLS_IETF_ELI_LABEL:
45       s = format (s, "%s", MPLS_IETF_ELI_STRING);
46       break;
47   case MPLS_IETF_GAL_LABEL:
48       s = format (s, "%s", MPLS_IETF_GAL_STRING);
49       break;
50   default:
51       s = format (s, "%d", label);
52       break;
53   }
54   return s;
55 }
56
57 uword unformat_mpls_unicast_label (unformat_input_t * input, va_list * args)
58 {
59   mpls_label_t *label = va_arg (*args, mpls_label_t*);
60   
61   if (unformat (input, MPLS_IETF_IPV4_EXPLICIT_NULL_STRING))
62       *label = MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL;
63   else if (unformat (input, MPLS_IETF_IPV6_EXPLICIT_NULL_STRING))
64       *label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL;
65   else if (unformat (input, MPLS_IETF_ROUTER_ALERT_STRING))
66       *label = MPLS_IETF_ROUTER_ALERT_LABEL;
67   else if (unformat (input, MPLS_IETF_IMPLICIT_NULL_STRING))
68       *label = MPLS_IETF_IMPLICIT_NULL_LABEL;
69   else if (unformat (input, "%d", label))
70       ;
71
72   return (1);
73 }
74
75 u8 * format_mpls_eos_bit (u8 * s, va_list * args)
76 {
77   mpls_eos_bit_t eb = va_arg (*args, mpls_eos_bit_t);
78
79   ASSERT(eb <= MPLS_EOS);
80
81   s = format(s, "%s", mpls_eos_bit_names[eb]);
82
83   return (s);
84 }
85
86 u8 * format_mpls_header (u8 * s, va_list * args)
87 {
88   mpls_unicast_header_t hdr = va_arg (*args, mpls_unicast_header_t);
89
90   return (format(s, "[%U:%d:%d:%U]",
91                  format_mpls_unicast_label, 
92                  vnet_mpls_uc_get_label(hdr.label_exp_s_ttl),
93                  vnet_mpls_uc_get_ttl(hdr.label_exp_s_ttl),
94                  vnet_mpls_uc_get_exp(hdr.label_exp_s_ttl),
95                  format_mpls_eos_bit,
96                  vnet_mpls_uc_get_s(hdr.label_exp_s_ttl)));
97 }
98
99 uword
100 unformat_mpls_header (unformat_input_t * input, va_list * args)
101 {
102   u8 ** result = va_arg (*args, u8 **);
103   mpls_unicast_header_t _h, * h = &_h;
104   u32 label, label_exp_s_ttl;
105
106   if (! unformat (input, "MPLS %d", &label))
107     return 0;
108
109   label_exp_s_ttl = (label<<12) | (1<<8) /* s-bit */ | 0xFF;
110   h->label_exp_s_ttl = clib_host_to_net_u32 (label_exp_s_ttl);
111
112   /* Add gre, mpls headers to result. */
113   {
114     void * p;
115     u32 h_n_bytes = sizeof (h[0]);
116
117     vec_add2 (*result, p, h_n_bytes);
118     clib_memcpy (p, h, h_n_bytes);
119   }
120
121   return 1;
122 }
123
124 uword
125 unformat_mpls_label_net_byte_order (unformat_input_t * input,
126                                         va_list * args)
127 {
128   u32 * result = va_arg (*args, u32 *);
129   u32 label;
130
131   if (!unformat (input, "MPLS: label %d", &label))
132     return 0;
133
134   label = (label<<12) | (1<<8) /* s-bit set */ | 0xFF /* ttl */;
135
136   *result = clib_host_to_net_u32 (label);
137   return 1;
138 }
139
140 u8 * format_mpls_unicast_header_host_byte_order (u8 * s, va_list * args)
141 {
142   mpls_unicast_header_t *h = va_arg(*args, mpls_unicast_header_t *);
143   u32 label = h->label_exp_s_ttl;
144   
145   s = format (s, "label %d exp %d, s %d, ttl %d",
146               vnet_mpls_uc_get_label (label),
147               vnet_mpls_uc_get_exp (label),
148               vnet_mpls_uc_get_s (label),
149               vnet_mpls_uc_get_ttl (label));
150   return s;
151 }
152
153 u8 * format_mpls_unicast_header_net_byte_order (u8 * s, va_list * args)
154 {
155   mpls_unicast_header_t *h = va_arg(*args, mpls_unicast_header_t *);
156   mpls_unicast_header_t h_host;
157
158   h_host.label_exp_s_ttl = clib_net_to_host_u32 (h->label_exp_s_ttl);
159
160   return format (s, "%U", format_mpls_unicast_header_host_byte_order,
161                  &h_host);
162 }
163
164 int
165 mpls_dest_cmp(void * a1, void * a2)
166 {
167   show_mpls_fib_t * r1 = a1;
168   show_mpls_fib_t * r2 = a2;
169
170   return clib_net_to_host_u32(r1->dest) - clib_net_to_host_u32(r2->dest);
171 }
172
173 int
174 mpls_fib_index_cmp(void * a1, void * a2)
175 {
176   show_mpls_fib_t * r1 = a1;
177   show_mpls_fib_t * r2 = a2;
178
179   return r1->fib_index - r2->fib_index;
180 }
181
182 int
183 mpls_label_cmp(void * a1, void * a2)
184 {
185   show_mpls_fib_t * r1 = a1;
186   show_mpls_fib_t * r2 = a2;
187
188   return r1->label - r2->label;
189 }
190
191 static clib_error_t *
192 vnet_mpls_local_label (vlib_main_t * vm,
193                        unformat_input_t * input,
194                        vlib_cli_command_t * cmd)
195 {
196   unformat_input_t _line_input, * line_input = &_line_input;
197   fib_route_path_t *rpaths = NULL, rpath;
198   u32 table_id, is_del, is_ip;
199   mpls_label_t local_label;
200   mpls_label_t out_label;
201   clib_error_t * error;
202   mpls_eos_bit_t eos;
203   vnet_main_t * vnm;
204   fib_prefix_t pfx;
205
206   vnm = vnet_get_main();
207   error = NULL;
208   is_ip = 0;
209   table_id = 0;
210   eos = MPLS_EOS;
211   is_del = 0;
212   local_label = MPLS_LABEL_INVALID;
213   memset(&pfx, 0, sizeof(pfx));
214
215    /* Get a line of input. */
216   if (! unformat_user (input, unformat_line_input, line_input))
217     return 0;
218
219   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
220     {
221       memset(&rpath, 0, sizeof(rpath));
222
223       if (unformat (line_input, "table %d", &table_id))
224         ;
225       else if (unformat (line_input, "del"))
226         is_del = 1;
227       else if (unformat (line_input, "add"))
228         is_del = 0;
229       else if (unformat (line_input, "eos"))
230         pfx.fp_eos = MPLS_EOS;
231       else if (unformat (line_input, "non-eos"))
232         pfx.fp_eos = MPLS_NON_EOS;
233       else if (unformat (line_input, "%U/%d",
234                          unformat_ip4_address,
235                          &pfx.fp_addr.ip4,
236                          &pfx.fp_len))
237       {
238           pfx.fp_proto = FIB_PROTOCOL_IP4;
239           is_ip = 1;
240       }
241       else if (unformat (line_input, "%U/%d",
242                          unformat_ip6_address,
243                          &pfx.fp_addr.ip6,
244                          &pfx.fp_len))
245       {
246           pfx.fp_proto = FIB_PROTOCOL_IP6;
247           is_ip = 1;
248       }
249       else if (unformat (line_input, "via %U %U weight %u",
250                          unformat_ip4_address,
251                          &rpath.frp_addr.ip4,
252                          unformat_vnet_sw_interface, vnm,
253                          &rpath.frp_sw_if_index,
254                          &rpath.frp_weight))
255       {
256           rpath.frp_proto = FIB_PROTOCOL_IP4;
257           vec_add1(rpaths, rpath);
258       }
259
260       else if (unformat (line_input, "via %U %U weight %u",
261                          unformat_ip6_address,
262                          &rpath.frp_addr.ip6,
263                          unformat_vnet_sw_interface, vnm,
264                          &rpath.frp_sw_if_index,
265                          &rpath.frp_weight))
266       {
267           rpath.frp_proto = FIB_PROTOCOL_IP6;
268           vec_add1(rpaths, rpath);
269       }
270
271       else if (unformat (line_input, "via %U %U",
272                          unformat_ip4_address,
273                          &rpath.frp_addr.ip4,
274                          unformat_vnet_sw_interface, vnm,
275                          &rpath.frp_sw_if_index))
276       {
277           rpath.frp_weight = 1;
278           rpath.frp_proto = FIB_PROTOCOL_IP4;
279           vec_add1(rpaths, rpath);
280       }
281                          
282       else if (unformat (line_input, "via %U %U",
283                          unformat_ip6_address,
284                          &rpath.frp_addr.ip6,
285                          unformat_vnet_sw_interface, vnm,
286                          &rpath.frp_sw_if_index))
287       {
288           rpath.frp_weight = 1;
289           rpath.frp_proto = FIB_PROTOCOL_IP6;
290           vec_add1(rpaths, rpath);
291       }
292       else if (unformat (line_input, "via %U next-hop-table %d",
293                          unformat_ip4_address,
294                          &rpath.frp_addr.ip4,
295                          &rpath.frp_fib_index))
296       {
297           rpath.frp_weight = 1;
298           rpath.frp_sw_if_index = ~0;
299           rpath.frp_proto = FIB_PROTOCOL_IP4;
300           vec_add1(rpaths, rpath);
301       }
302       else if (unformat (line_input, "via %U next-hop-table %d",
303                          unformat_ip6_address,
304                          &rpath.frp_addr.ip6,
305                          &rpath.frp_fib_index))
306       {
307           rpath.frp_weight = 1;
308           rpath.frp_sw_if_index = ~0;
309           rpath.frp_proto = FIB_PROTOCOL_IP6;
310           vec_add1(rpaths, rpath);
311       }
312       else if (unformat (line_input, "via %U",
313                          unformat_ip4_address,
314                          &rpath.frp_addr.ip4))
315       {
316           /*
317            * the recursive next-hops are by default in the same table
318            * as the prefix
319            */
320           rpath.frp_fib_index = table_id;
321           rpath.frp_weight = 1;
322           rpath.frp_sw_if_index = ~0;
323           rpath.frp_proto = FIB_PROTOCOL_IP4;
324           vec_add1(rpaths, rpath);
325       }
326       else if (unformat (line_input, "via %U",
327                          unformat_ip6_address,
328                          &rpath.frp_addr.ip6))
329       {
330           rpath.frp_fib_index = table_id;
331           rpath.frp_weight = 1;
332           rpath.frp_sw_if_index = ~0;
333           rpath.frp_proto = FIB_PROTOCOL_IP6;
334           vec_add1(rpaths, rpath);
335       }
336       else if (unformat (line_input, "%d", &local_label))
337         ;
338       else if (unformat (line_input,
339                          "ip4-lookup-in-table %d",
340                          &rpath.frp_fib_index))
341       {
342           rpath.frp_proto = FIB_PROTOCOL_IP4;
343           rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID;
344           pfx.fp_payload_proto = DPO_PROTO_IP4;
345           vec_add1(rpaths, rpath);
346       }
347       else if (unformat (line_input,
348                          "ip6-lookup-in-table %d",
349                          &rpath.frp_fib_index))
350       {
351           rpath.frp_proto = FIB_PROTOCOL_IP6;
352           rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID;
353           vec_add1(rpaths, rpath);
354           pfx.fp_payload_proto = DPO_PROTO_IP6;
355       }
356       else if (unformat (line_input,
357                          "mpls-lookup-in-table %d",
358                          &rpath.frp_fib_index))
359       {
360           rpath.frp_proto = FIB_PROTOCOL_MPLS;
361           rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID;
362           pfx.fp_payload_proto = DPO_PROTO_MPLS;
363           vec_add1(rpaths, rpath);
364       }
365       else if (unformat (line_input, "out-label %U",
366                          unformat_mpls_unicast_label,
367                          &out_label))
368       {
369           if (vec_len(rpaths) == 0)
370           {
371               error = clib_error_return(0 , "Paths then labels");
372               goto done;
373           }
374           vec_add1(rpaths[vec_len(rpaths)-1].frp_label_stack, out_label);
375       }
376       else
377       {
378           error = clib_error_return (0, "unkown input: %U",
379                                      format_unformat_error, line_input);
380           goto done;
381       }
382
383     }
384
385   if (MPLS_LABEL_INVALID == local_label)
386   {
387       error = clib_error_return (0, "local-label required: %U",
388                                  format_unformat_error, input);
389       goto done;
390   }
391
392
393   if (is_ip)
394   {
395       u32 fib_index = fib_table_find(pfx.fp_proto, table_id);
396
397       if (FIB_NODE_INDEX_INVALID == fib_index)
398       {
399           error = clib_error_return (0, "%U table-id %d does not exist",
400                                      format_fib_protocol, pfx.fp_proto, table_id);
401           goto done;
402       }
403
404       if (is_del)
405       {
406           fib_table_entry_local_label_remove(fib_index, &pfx, local_label);
407       }
408       else
409       {
410           fib_table_entry_local_label_add(fib_index, &pfx, local_label);
411       }
412   }
413   else
414   {
415       fib_node_index_t lfe, fib_index;
416       u32 fi;
417
418       if (NULL == rpaths)
419       {
420           error = clib_error_return(0 , "no paths");
421           goto done;
422       }
423
424       pfx.fp_proto = FIB_PROTOCOL_MPLS;
425       pfx.fp_len = 21;
426       pfx.fp_label = local_label;
427       pfx.fp_payload_proto = fib_proto_to_dpo(rpaths[0].frp_proto);
428
429       /*
430        * the CLI parsing stored table Ids, swap to FIB indicies
431        */
432       if (FIB_NODE_INDEX_INVALID == rpath.frp_sw_if_index)
433       {
434           fi = fib_table_id_find_fib_index(dpo_proto_to_fib(pfx.fp_payload_proto),
435                                            rpaths[0].frp_fib_index);
436
437           if (~0 == fi)
438           {
439               error = clib_error_return(0 , "%U Via table %d does not exist",
440                                         format_dpo_proto, pfx.fp_payload_proto,
441                                         rpaths[0].frp_fib_index);
442               goto done;
443           }
444           rpaths[0].frp_fib_index = fi;
445       }
446
447       fib_index = mpls_fib_index_from_table_id(table_id);
448
449       if (FIB_NODE_INDEX_INVALID == fib_index)
450       {
451           error = clib_error_return (0, "MPLS table-id %d does not exist",
452                                      table_id);
453           goto done;
454       }
455
456       lfe = fib_table_entry_path_add2(fib_index,
457                                       &pfx,
458                                       FIB_SOURCE_CLI,
459                                       FIB_ENTRY_FLAG_NONE,
460                                       rpaths);
461
462       if (FIB_NODE_INDEX_INVALID == lfe)
463       {
464           error = clib_error_return (0, "Failed to create %U-%U in MPLS table-id %d",
465                                      format_mpls_unicast_label, local_label,
466                                      format_mpls_eos_bit, eos,
467                                      table_id);
468           goto done;
469       }
470   }
471
472 done:
473   return error;
474 }
475
476 VLIB_CLI_COMMAND (mpls_local_label_command, static) = {
477   .path = "mpls local-label",
478   .function = vnet_mpls_local_label,
479   .short_help = "Create/Delete MPL local labels",
480 };
481
482 int
483 mpls_fib_reset_labels (u32 fib_id)
484 {
485   // FIXME
486   return 0;
487 }
488
489 static clib_error_t *
490 mpls_init (vlib_main_t * vm)
491 {
492   mpls_main_t * mm = &mpls_main;
493   clib_error_t * error;
494
495   mm->vlib_main = vm;
496   mm->vnet_main = vnet_get_main();
497
498   if ((error = vlib_call_init_function (vm, ip_main_init)))
499     return error;
500
501   return vlib_call_init_function (vm, mpls_input_init);
502 }
503
504 VLIB_INIT_FUNCTION (mpls_init);
505
506 mpls_main_t * mpls_get_main (vlib_main_t * vm)
507 {
508   vlib_call_init_function (vm, mpls_init);
509   return &mpls_main;
510 }
511