b28736ba5a767d45f0d007d16d70d8520afee74a
[vpp.git] / vnet / 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 u8 * format_mpls_gre_tx_trace (u8 * s, va_list * args)
100 {
101   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
102   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
103   mpls_gre_tx_trace_t * t = va_arg (*args, mpls_gre_tx_trace_t *);
104   mpls_main_t * mm = &mpls_main;
105     
106   if (t->lookup_miss)
107     s = format (s, "MPLS: lookup miss");
108   else
109     {
110       s = format (s, "MPLS: tunnel %d labels %U len %d src %U dst %U",
111                   t->tunnel_id,
112                   format_mpls_encap_index, mm, t->mpls_encap_index, 
113                   clib_net_to_host_u16 (t->length),
114                   format_ip4_address, &t->src.as_u8,
115                   format_ip4_address, &t->dst.as_u8);
116     }
117   return s;
118 }
119
120 u8 * format_mpls_eth_tx_trace (u8 * s, va_list * args)
121 {
122   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
123   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
124   mpls_eth_tx_trace_t * t = va_arg (*args, mpls_eth_tx_trace_t *);
125   mpls_main_t * mm = &mpls_main;
126     
127   if (t->lookup_miss)
128     s = format (s, "MPLS: lookup miss");
129   else
130     {
131       s = format (s, "MPLS: tunnel %d labels %U len %d tx_sw_index %d dst %U",
132                   t->tunnel_id,
133                   format_mpls_encap_index, mm, t->mpls_encap_index, 
134                   clib_net_to_host_u16 (t->length),
135                   t->tx_sw_if_index, 
136                   format_ethernet_address, t->dst);
137     }
138   return s;
139 }
140
141 u8 * format_mpls_eth_header_with_length (u8 * s, va_list * args)
142 {
143   ethernet_header_t * h = va_arg (*args, ethernet_header_t *);
144   mpls_unicast_header_t * m = (mpls_unicast_header_t *)(h+1);
145   u32 max_header_bytes = va_arg (*args, u32);
146   uword header_bytes;
147
148   header_bytes = sizeof (h[0]);
149   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
150     return format (s, "ethernet header truncated");
151
152   s = format 
153     (s, "ETHERNET-MPLS label %d", 
154      vnet_mpls_uc_get_label (clib_net_to_host_u32 (m->label_exp_s_ttl)));
155
156   return s;
157 }
158
159 u8 * format_mpls_gre_header_with_length (u8 * s, va_list * args)
160 {
161   gre_header_t * h = va_arg (*args, gre_header_t *);
162   mpls_unicast_header_t * m = (mpls_unicast_header_t *)(h+1);
163   u32 max_header_bytes = va_arg (*args, u32);
164   uword header_bytes;
165
166   header_bytes = sizeof (h[0]);
167   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
168     return format (s, "gre header truncated");
169
170   s = format 
171     (s, "GRE-MPLS label %d", 
172      vnet_mpls_uc_get_label (clib_net_to_host_u32 (m->label_exp_s_ttl)));
173
174   return s;
175 }
176
177 u8 * format_mpls_gre_header (u8 * s, va_list * args)
178 {
179   gre_header_t * h = va_arg (*args, gre_header_t *);
180   return format (s, "%U", format_mpls_gre_header_with_length, h, 0);
181 }
182
183 uword
184 unformat_mpls_gre_header (unformat_input_t * input, va_list * args)
185 {
186   u8 ** result = va_arg (*args, u8 **);
187   gre_header_t _g, * g = &_g;
188   mpls_unicast_header_t _h, * h = &_h;
189   u32 label, label_exp_s_ttl;
190   
191   if (! unformat (input, "MPLS %d", &label))
192     return 0;
193
194   g->protocol = clib_host_to_net_u16 (GRE_PROTOCOL_mpls_unicast);
195
196   label_exp_s_ttl = (label<<12) | (1<<8) /* s-bit */ | 0xFF;
197   h->label_exp_s_ttl = clib_host_to_net_u32 (label_exp_s_ttl);
198
199   /* Add gre, mpls headers to result. */
200   {
201     void * p;
202     u32 g_n_bytes = sizeof (g[0]);
203     u32 h_n_bytes = sizeof (h[0]);
204
205     vec_add2 (*result, p, g_n_bytes);
206     clib_memcpy (p, g, g_n_bytes);
207
208     vec_add2 (*result, p, h_n_bytes);
209     clib_memcpy (p, h, h_n_bytes);
210   }
211   
212   return 1;
213 }
214
215 uword
216 unformat_mpls_label_net_byte_order (unformat_input_t * input,
217                                         va_list * args)
218 {
219   u32 * result = va_arg (*args, u32 *);
220   u32 label;
221
222   if (!unformat (input, "MPLS: label %d", &label))
223     return 0;
224
225   label = (label<<12) | (1<<8) /* s-bit set */ | 0xFF /* ttl */;
226
227   *result = clib_host_to_net_u32 (label);
228   return 1;
229 }
230
231 mpls_encap_t * 
232 mpls_encap_by_fib_and_dest (mpls_main_t * mm, u32 rx_fib, u32 dst_address)
233 {
234   uword * p;
235   mpls_encap_t * e;
236   u64 key;
237
238   key = ((u64)rx_fib<<32) | ((u64) dst_address);
239   p = hash_get (mm->mpls_encap_by_fib_and_dest, key);
240
241   if (!p)
242     return 0;
243
244   e = pool_elt_at_index (mm->encaps, p[0]);
245   return e;
246 }
247
248 int vnet_mpls_add_del_encap (ip4_address_t *dest, u32 fib_id, 
249                              u32 *labels_host_byte_order,
250                              u32 policy_tunnel_index,
251                              int no_dst_hash, u32 * indexp, int is_add)
252 {
253   mpls_main_t * mm = &mpls_main;
254   ip4_main_t * im = &ip4_main;
255   mpls_encap_t * e;
256   u32 label_net_byte_order, label_host_byte_order;
257   u32 fib_index;
258   u64 key;
259   uword *p;
260   int i;
261   
262   p = hash_get (im->fib_index_by_table_id, fib_id);
263   if (! p)
264     return VNET_API_ERROR_NO_SUCH_FIB;
265   
266   fib_index = p[0];
267   
268   key = ((u64)fib_index<<32) | ((u64) dest->as_u32);
269   
270   if (is_add)
271     {
272       pool_get (mm->encaps, e);
273       memset (e, 0, sizeof (*e));
274       
275       for (i = 0; i < vec_len (labels_host_byte_order); i++)
276         {
277           mpls_unicast_header_t h;
278           label_host_byte_order = labels_host_byte_order[i];
279           
280           /* Reformat label into mpls_unicast_header_t */
281           label_host_byte_order <<= 12;
282           // FIXME NEOS AND EOS
283           //if (i == vec_len(labels_host_byte_order) - 1)
284           //  label_host_byte_order |= 1<<8;            /* S=1 */
285           label_host_byte_order |= 0xff;            /* TTL=FF */
286           label_net_byte_order = clib_host_to_net_u32 (label_host_byte_order);
287           h.label_exp_s_ttl = label_net_byte_order;
288           vec_add1 (e->labels, h);
289         }
290       if (no_dst_hash == 0)
291         hash_set (mm->mpls_encap_by_fib_and_dest, key, e - mm->encaps);
292       if (indexp)
293         *indexp = e - mm->encaps;
294       if (policy_tunnel_index != ~0)
295         return vnet_mpls_policy_tunnel_add_rewrite (mm, e, policy_tunnel_index);
296     }
297   else
298     {
299       p = hash_get (mm->mpls_encap_by_fib_and_dest, key);
300       if (!p)
301         return VNET_API_ERROR_NO_SUCH_LABEL;
302       
303       e = pool_elt_at_index (mm->encaps, p[0]);
304       
305       vec_free (e->labels);
306       vec_free (e->rewrite);
307       pool_put(mm->encaps, e);
308       
309       if (no_dst_hash == 0)
310         hash_unset (mm->mpls_encap_by_fib_and_dest, key);    
311     }
312   return 0;
313 }
314
315 static clib_error_t *
316 mpls_add_encap_command_fn (vlib_main_t * vm,
317                            unformat_input_t * input,
318                            vlib_cli_command_t * cmd)
319 {
320   u32 fib_id;
321   u32 *labels = 0;
322   u32 this_label;
323   ip4_address_t dest;
324   u32 policy_tunnel_index = ~0;
325   int no_dst_hash = 0;
326   int rv;
327   int fib_set = 0;
328   int dest_set = 0;
329
330   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
331     {
332       if (unformat (input, "fib %d", &fib_id))
333         fib_set = 1;
334       else if (unformat (input, "dest %U", unformat_ip4_address, &dest))
335         dest_set = 1;
336       else if (unformat (input, "no-dst-hash"))
337         no_dst_hash = 1;
338       else if (unformat (input, "label %d", &this_label))
339         vec_add1 (labels, this_label);
340       else if (unformat (input, "policy-tunnel %d", &policy_tunnel_index))
341         ;
342       else
343         break;
344     }
345
346   if (fib_set == 0)
347     return clib_error_return (0, "fib-id missing");
348   if (dest_set == 0)
349     return clib_error_return (0, "destination IP address missing");
350   if (vec_len (labels) == 0)
351     return clib_error_return (0, "label stack missing");
352   
353   rv = vnet_mpls_add_del_encap (&dest, fib_id, labels, 
354                                 policy_tunnel_index, 
355                                 no_dst_hash, 0 /* indexp */,
356                                 1 /* is_add */);
357   vec_free (labels);
358
359   switch (rv)
360     {
361     case 0:
362       break;
363
364     case VNET_API_ERROR_NO_SUCH_FIB:
365       return clib_error_return (0, "fib id %d unknown", fib_id);
366       
367     default:
368       return clib_error_return (0, "vnet_mpls_add_del_encap returned %d", 
369                                 rv);
370     }
371
372   return 0;
373 }
374
375 VLIB_CLI_COMMAND (mpls_add_encap_command, static) = {
376   .path = "mpls encap add",
377   .short_help = 
378   "mpls encap add label <label> ... fib <id> dest <ip4-address>",
379   .function = mpls_add_encap_command_fn,
380 };
381
382 u8 * format_mpls_unicast_header_host_byte_order (u8 * s, va_list * args)
383 {
384   mpls_unicast_header_t *h = va_arg(*args, mpls_unicast_header_t *);
385   u32 label = h->label_exp_s_ttl;
386   
387   s = format (s, "label %d exp %d, s %d, ttl %d",
388               vnet_mpls_uc_get_label (label),
389               vnet_mpls_uc_get_exp (label),
390               vnet_mpls_uc_get_s (label),
391               vnet_mpls_uc_get_ttl (label));
392   return s;
393 }
394
395 u8 * format_mpls_unicast_header_net_byte_order (u8 * s, va_list * args)
396 {
397   mpls_unicast_header_t *h = va_arg(*args, mpls_unicast_header_t *);
398   mpls_unicast_header_t h_host;
399
400   h_host.label_exp_s_ttl = clib_net_to_host_u32 (h->label_exp_s_ttl);
401
402   return format (s, "%U", format_mpls_unicast_header_host_byte_order,
403                  &h_host);
404 }
405
406 static clib_error_t *
407 mpls_del_encap_command_fn (vlib_main_t * vm,
408                  unformat_input_t * input,
409                  vlib_cli_command_t * cmd)
410 {
411   u32 fib_id;
412   ip4_address_t dest;
413   int rv;
414   
415   if (unformat (input, "fib %d dest %U", &fib_id, 
416                 unformat_ip4_address, &dest)) 
417     {
418       rv = vnet_mpls_add_del_encap (&dest, fib_id, 0 /* labels */, 
419                                     ~0 /* policy_tunnel_index */,
420                                     0 /* no_dst_hash */,
421                                     0 /* indexp */,
422                                     0 /* is_add */);
423       switch (rv)
424         {
425         case VNET_API_ERROR_NO_SUCH_FIB:
426           return clib_error_return (0, "fib id %d unknown", fib_id);
427         case VNET_API_ERROR_NO_SUCH_ENTRY:
428           return clib_error_return (0, "dest %U not in fib %d",
429                                     format_ip4_address, &dest, fib_id);
430         default:
431           break;
432         }
433       return 0;
434     }
435   else
436     return clib_error_return (0, "unknown input `%U'",
437                               format_unformat_error, input);
438 }
439
440 VLIB_CLI_COMMAND (mpls_del_encap_command, static) = {
441   .path = "mpls encap delete",
442   .short_help = "mpls encap delete fib <id> dest <ip4-address>",
443   .function = mpls_del_encap_command_fn,
444 };
445
446 int vnet_mpls_add_del_decap (u32 rx_fib_id, 
447                              u32 tx_fib_id,
448                              u32 label_host_byte_order, 
449                              int s_bit, int next_index, int is_add)
450 {
451   mpls_main_t * mm = &mpls_main;
452   ip4_main_t * im = &ip4_main;
453   mpls_decap_t * d;
454   u32 rx_fib_index, tx_fib_index_or_output_swif_index;
455   uword *p;
456   u64 key;
457   
458   p = hash_get (im->fib_index_by_table_id, rx_fib_id);
459   if (! p)
460     return VNET_API_ERROR_NO_SUCH_FIB;
461
462   rx_fib_index = p[0];
463
464   /* L3 decap => transform fib ID to fib index */
465   if (next_index == MPLS_LOOKUP_NEXT_IP4_INPUT)
466     {
467       p = hash_get (im->fib_index_by_table_id, tx_fib_id);
468       if (! p)
469         return VNET_API_ERROR_NO_SUCH_INNER_FIB;
470       
471       tx_fib_index_or_output_swif_index = p[0];
472     }
473   else
474     {
475       /* L2 decap, tx_fib_id is actually the output sw_if_index */
476       tx_fib_index_or_output_swif_index = tx_fib_id;
477     }
478
479   key = ((u64) rx_fib_index<<32) | ((u64) label_host_byte_order<<12)
480     | ((u64) s_bit<<8);
481
482   p = hash_get (mm->mpls_decap_by_rx_fib_and_label, key);
483
484   /* If deleting, or replacing an old entry */
485   if (is_add == 0 || p)
486     {
487       if (is_add == 0 && p == 0)
488         return VNET_API_ERROR_NO_SUCH_LABEL;
489
490       d = pool_elt_at_index (mm->decaps, p[0]);
491       hash_unset (mm->mpls_decap_by_rx_fib_and_label, key);
492       pool_put (mm->decaps, d);
493       /* Deleting, we're done... */
494       if (is_add == 0)
495         return 0;
496     }
497
498   /* add decap entry... */
499   pool_get (mm->decaps, d);
500   memset (d, 0, sizeof (*d));
501   d->tx_fib_index = tx_fib_index_or_output_swif_index;
502   d->next_index = next_index;
503
504   hash_set (mm->mpls_decap_by_rx_fib_and_label, key, d - mm->decaps);
505
506   return 0;
507 }
508
509 uword
510 unformat_mpls_gre_input_next (unformat_input_t * input, va_list * args)
511 {
512   u32 * result = va_arg (*args, u32 *);
513   int rv = 0;
514
515   if (unformat (input, "lookup"))
516     {
517       *result = MPLS_LOOKUP_NEXT_IP4_INPUT;
518       rv = 1;
519     }
520   else if (unformat (input, "output"))
521     {
522       *result = MPLS_LOOKUP_NEXT_L2_OUTPUT;
523       rv = 1;
524     }
525   return rv;
526 }
527
528 static clib_error_t *
529 mpls_add_decap_command_fn (vlib_main_t * vm,
530                            unformat_input_t * input,
531                            vlib_cli_command_t * cmd)
532 {
533   vnet_main_t * vnm = vnet_get_main();
534   u32 rx_fib_id = 0;
535   u32 tx_fib_or_sw_if_index;
536   u32 label;
537   int s_bit = 1;
538   u32 next_index = 1;           /* ip4_lookup, see node.c */
539   int tx_fib_id_set = 0;
540   int label_set = 0;
541   int rv;
542
543   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
544     {
545       if (unformat (input, "fib %d", &tx_fib_or_sw_if_index))
546         tx_fib_id_set = 1;
547       else if (unformat (input, "sw_if_index %d", &tx_fib_or_sw_if_index))
548         tx_fib_id_set = 1;
549       else if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
550                          &tx_fib_or_sw_if_index))
551         tx_fib_id_set = 1;
552       else if (unformat (input, "rx-fib %d", &rx_fib_id))
553         ;
554       else if (unformat (input, "label %d", &label))
555         label_set = 1;
556       else if (unformat (input, "s-bit-clear"))
557         s_bit = 0;
558       else if (unformat (input, "next %U", unformat_mpls_gre_input_next, 
559                          &next_index))
560         ;
561       else
562         break;
563     }
564
565   if (tx_fib_id_set == 0)
566     return clib_error_return (0, "lookup FIB ID not set");
567   if (label_set == 0)
568     return clib_error_return (0, "missing label");
569   
570   rv = vnet_mpls_add_del_decap (rx_fib_id, tx_fib_or_sw_if_index, 
571                                 label, s_bit, next_index, 1 /* is_add */);
572   switch (rv)
573     {
574     case 0:
575       break;
576
577     case VNET_API_ERROR_NO_SUCH_FIB:
578       return clib_error_return (0, "no such rx fib id %d", rx_fib_id);
579
580     case VNET_API_ERROR_NO_SUCH_INNER_FIB:
581       return clib_error_return (0, "no such tx fib / swif %d", 
582                                 tx_fib_or_sw_if_index);
583
584     default:
585       return clib_error_return (0, "vnet_mpls_add_del_decap returned %d",
586                                 rv);
587     }
588   return 0;
589 }
590
591 VLIB_CLI_COMMAND (mpls_add_decap_command, static) = {
592     .path = "mpls decap add",
593     .short_help = 
594     "mpls decap add fib <id> label <nn> [s-bit-clear] [next-index <nn>]",
595     .function = mpls_add_decap_command_fn, 
596 };
597
598 static clib_error_t *
599 mpls_del_decap_command_fn (vlib_main_t * vm,
600                            unformat_input_t * input,
601                            vlib_cli_command_t * cmd)
602 {
603   u32 rx_fib_id = 0;
604   u32 tx_fib_id = 0;
605   u32 label;
606   int s_bit = 1;
607   int label_set = 0;
608   int rv;
609
610   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
611     {
612       if (unformat (input, "rx-fib %d", &rx_fib_id))
613         ;
614       else if (unformat (input, "label %d", &label))
615         label_set = 1;
616       else if (unformat (input, "s-bit-clear"))
617         s_bit = 0;
618     }
619
620   if (!label_set)
621     return clib_error_return (0, "label not set");
622
623   rv = vnet_mpls_add_del_decap (rx_fib_id, 
624                                 tx_fib_id /* not interesting */,
625                                 label, s_bit, 
626                                 0 /* next_index not interesting */,
627                                 0 /* is_add */);
628   switch (rv)
629     {
630     case 0:
631       break;
632
633     case VNET_API_ERROR_NO_SUCH_FIB:
634       return clib_error_return (0, "no such rx fib id %d", rx_fib_id);
635
636     case VNET_API_ERROR_NO_SUCH_INNER_FIB:
637       return clib_error_return (0, "no such lookup fib id %d", tx_fib_id);
638
639     case VNET_API_ERROR_NO_SUCH_LABEL:
640       return clib_error_return (0, "no such label %d rx fib id %d", 
641                                 label, rx_fib_id);
642
643     default:
644       return clib_error_return (0, "vnet_mpls_add_del_decap returned %d",
645                                 rv);
646     }
647   return 0;
648 }
649
650
651 VLIB_CLI_COMMAND (mpls_del_decap_command, static) = {
652   .path = "mpls decap delete",
653   .short_help = "mpls decap delete label <label> rx-fib <id> [s-bit-clear]",
654   .function = mpls_del_decap_command_fn,
655 };
656
657 int
658 mpls_dest_cmp(void * a1, void * a2)
659 {
660   show_mpls_fib_t * r1 = a1;
661   show_mpls_fib_t * r2 = a2;
662
663   return clib_net_to_host_u32(r1->dest) - clib_net_to_host_u32(r2->dest);
664 }
665
666 int
667 mpls_fib_index_cmp(void * a1, void * a2)
668 {
669   show_mpls_fib_t * r1 = a1;
670   show_mpls_fib_t * r2 = a2;
671
672   return r1->fib_index - r2->fib_index;
673 }
674
675 int
676 mpls_label_cmp(void * a1, void * a2)
677 {
678   show_mpls_fib_t * r1 = a1;
679   show_mpls_fib_t * r2 = a2;
680
681   return r1->label - r2->label;
682 }
683
684 static clib_error_t *
685 show_mpls_fib_command_fn (vlib_main_t * vm,
686                  unformat_input_t * input,
687                  vlib_cli_command_t * cmd)
688 {
689   u64 key; 
690   u32 value;
691   show_mpls_fib_t *records = 0;
692   show_mpls_fib_t *s;
693   mpls_main_t * mm = &mpls_main;
694   ip4_fib_t * rx_fib;
695
696   hash_foreach (key, value, mm->mpls_encap_by_fib_and_dest, 
697   ({
698     vec_add2 (records, s, 1);
699     s->fib_index = (u32)(key>>32);
700     s->dest = (u32)(key & 0xFFFFFFFF);
701     s->entry_index = (u32) value;
702   }));
703
704   if (!vec_len(records))
705     {
706       vlib_cli_output (vm, "MPLS encap table empty");
707     }
708   /* sort output by dst address within fib */
709   vec_sort_with_function (records, mpls_dest_cmp);
710   vec_sort_with_function (records, mpls_fib_index_cmp);
711   vlib_cli_output (vm, "MPLS encap table");
712   vlib_cli_output (vm, "%=6s%=16s%=16s", "Table", "Dest address", "Labels");
713   vec_foreach (s, records)
714     {
715       rx_fib = ip4_fib_get (s->fib_index);
716       vlib_cli_output (vm, "%=6d%=16U%=16U", rx_fib->table_id, 
717                        format_ip4_address, &s->dest,
718                        format_mpls_encap_index, mm, s->entry_index);
719     }
720
721   vec_free(records);
722   return 0;
723 }
724
725 VLIB_CLI_COMMAND (show_mpls_fib_command, static) = {
726     .path = "show mpls encap",
727     .short_help = "show mpls encap",
728     .function = show_mpls_fib_command_fn,
729 };
730
731 static clib_error_t *
732 vnet_mpls_local_label (vlib_main_t * vm,
733                        unformat_input_t * input,
734                        vlib_cli_command_t * cmd)
735 {
736   unformat_input_t _line_input, * line_input = &_line_input;
737   fib_route_path_t *rpaths = NULL, rpath;
738   clib_error_t * error = 0;
739   u32 table_id, is_del, is_ip;
740   fib_prefix_t pfx;
741   mpls_label_t local_label;
742   mpls_eos_bit_t eos;
743
744   is_ip = 0;
745   table_id = 0;
746   eos = MPLS_EOS;
747   is_del = 0;
748   local_label = MPLS_LABEL_INVALID;
749   memset(&pfx, 0, sizeof(pfx));
750
751    /* Get a line of input. */
752   if (! unformat_user (input, unformat_line_input, line_input))
753     return 0;
754
755   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
756     {
757       memset(&rpath, 0, sizeof(rpath));
758
759       if (unformat (line_input, "table %d", &table_id))
760         ;
761       else if (unformat (line_input, "del"))
762         is_del = 1;
763       else if (unformat (line_input, "add"))
764         is_del = 0;
765       else if (unformat (line_input, "eos"))
766         pfx.fp_eos = MPLS_EOS;
767       else if (unformat (line_input, "non-eos"))
768         pfx.fp_eos = MPLS_NON_EOS;
769       else if (unformat (line_input, "%U/%d",
770                          unformat_ip4_address,
771                          &pfx.fp_addr.ip4,
772                          &pfx.fp_len))
773       {
774           pfx.fp_proto = FIB_PROTOCOL_IP4;
775           is_ip = 1;
776       }
777       else if (unformat (line_input, "%U/%d",
778                          unformat_ip6_address,
779                          &pfx.fp_addr.ip6,
780                          &pfx.fp_len))
781       {
782           pfx.fp_proto = FIB_PROTOCOL_IP6;
783           is_ip = 1;
784       }
785       else if (unformat (line_input, "%d", &local_label))
786         ;
787       else if (unformat (line_input,
788                          "ip4-lookup-in-table %d",
789                          &rpath.frp_fib_index))
790       {
791           rpath.frp_label = MPLS_LABEL_INVALID;
792           rpath.frp_proto = FIB_PROTOCOL_IP4;
793           rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID;
794           pfx.fp_payload_proto = FIB_PROTOCOL_IP4;
795           vec_add1(rpaths, rpath);
796       }
797       else if (unformat (line_input,
798                          "ip6-lookup-in-table %d",
799                          &rpath.frp_fib_index))
800       {
801           rpath.frp_label = MPLS_LABEL_INVALID;
802           rpath.frp_proto = FIB_PROTOCOL_IP6;
803           rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID;
804           vec_add1(rpaths, rpath);
805           pfx.fp_payload_proto = FIB_PROTOCOL_IP6;
806       }
807       else if (unformat (line_input,
808                          "mpls-lookup-in-table %d",
809                          &rpath.frp_fib_index))
810       {
811           rpath.frp_label = MPLS_LABEL_INVALID;
812           rpath.frp_proto = FIB_PROTOCOL_MPLS;
813           rpath.frp_sw_if_index = FIB_NODE_INDEX_INVALID;
814           pfx.fp_payload_proto = FIB_PROTOCOL_MPLS;
815           vec_add1(rpaths, rpath);
816       }
817       else
818       {
819           error = clib_error_return (0, "unkown input: %U",
820                                      format_unformat_error, input);
821           goto done;
822       }
823
824     }
825
826   if (MPLS_LABEL_INVALID == local_label)
827   {
828       error = clib_error_return (0, "local-label required: %U",
829                                  format_unformat_error, input);
830       goto done;
831   }
832
833
834   if (is_ip)
835   {
836       u32 fib_index = fib_table_find(pfx.fp_proto, table_id);
837
838       if (FIB_NODE_INDEX_INVALID == fib_index)
839       {
840           error = clib_error_return (0, "%U table-id %d does not exist",
841                                      format_fib_protocol, pfx.fp_proto, table_id);
842           goto done;
843       }
844
845       if (is_del)
846       {
847           fib_table_entry_local_label_remove(fib_index, &pfx, local_label);
848       }
849       else
850       {
851           fib_table_entry_local_label_add(fib_index, &pfx, local_label);
852       }
853   }
854   else
855   {
856       fib_node_index_t lfe, fib_index;
857       u32 fi;
858
859       pfx.fp_proto = FIB_PROTOCOL_MPLS;
860       pfx.fp_len = 21;
861       pfx.fp_label = local_label;
862
863       /*
864        * the CLI parsing stored table Ids, swap to FIB indicies
865        */
866       fi = fib_table_id_find_fib_index(pfx.fp_payload_proto,
867                                        rpaths[0].frp_fib_index);
868
869       if (~0 == fi)
870       {
871           error = clib_error_return(0 , "%U Via table %d does not exist",
872                                     format_fib_protocol, pfx.fp_payload_proto,
873                                     rpaths[0].frp_fib_index);
874           goto done;
875       }
876       rpaths[0].frp_fib_index = fi;
877
878       fib_index = mpls_fib_index_from_table_id(table_id);
879
880       if (FIB_NODE_INDEX_INVALID == fib_index)
881       {
882           error = clib_error_return (0, "MPLS table-id %d does not exist",
883                                      table_id);
884           goto done;
885       }
886
887       lfe = fib_table_entry_path_add2(fib_index,
888                                       &pfx,
889                                       FIB_SOURCE_CLI,
890                                       FIB_ENTRY_FLAG_NONE,
891                                       rpaths);
892
893       if (FIB_NODE_INDEX_INVALID == lfe)
894       {
895           error = clib_error_return (0, "Failed to create %U-%U in MPLS table-id %d",
896                                      format_mpls_unicast_label, local_label,
897                                      format_mpls_eos_bit, eos,
898                                      table_id);
899           goto done;
900       }
901   }
902
903 done:
904   return error;
905 }
906
907 VLIB_CLI_COMMAND (mpls_local_label_command, static) = {
908   .path = "mpls local-label",
909   .function = vnet_mpls_local_label,
910   .short_help = "Create/Delete MPL local labels",
911 };
912
913 int mpls_fib_reset_labels (u32 fib_id)
914 {
915   u64 key; 
916   u32 value;
917   show_mpls_fib_t *records = 0;
918   show_mpls_fib_t *s;
919   mpls_main_t * mm = &mpls_main;
920   ip4_main_t * im = &ip4_main;
921   u32 fib_index;
922   uword *p;
923
924   p = hash_get (im->fib_index_by_table_id, fib_id);
925   if (! p)
926     return VNET_API_ERROR_NO_SUCH_FIB;
927
928   fib_index = p[0];
929
930   hash_foreach (key, value, mm->mpls_encap_by_fib_and_dest, 
931   ({
932     if (fib_index == (u32)(key>>32)) {
933         vec_add2 (records, s, 1);
934         s->dest = (u32)(key & 0xFFFFFFFF);
935         s->entry_index = (u32) value;
936     }
937   }));
938
939   vec_foreach (s, records)
940     {
941       key = ((u64)fib_index<<32) | ((u64) s->dest);
942       hash_unset (mm->mpls_encap_by_fib_and_dest, key);
943       pool_put_index (mm->encaps, s->entry_index);
944     }
945                 
946   vec_reset_length(records);
947
948   hash_foreach (key, value, mm->mpls_decap_by_rx_fib_and_label, 
949   ({
950     if (fib_index == (u32) (key>>32)) {
951         vec_add2 (records, s, 1);
952         s->entry_index = value;
953         s->fib_index = fib_index;
954         s->s_bit = key & (1<<8);
955         s->dest = (u32)((key & 0xFFFFFFFF)>>12);
956     }
957   }));
958   
959   vec_foreach (s, records)
960     {
961        key = ((u64) fib_index <<32) | ((u64) s->dest<<12) |
962         ((u64) s->s_bit);
963       
964       hash_unset (mm->mpls_decap_by_rx_fib_and_label, key);
965       pool_put_index (mm->decaps, s->entry_index);
966     }
967
968   vec_free(records);
969   return 0;
970 }
971
972 static clib_error_t * mpls_init (vlib_main_t * vm)
973 {
974   mpls_main_t * mm = &mpls_main;
975   clib_error_t * error;
976
977   mm->vlib_main = vm;
978   mm->vnet_main = vnet_get_main();
979
980   if ((error = vlib_call_init_function (vm, ip_main_init)))
981     return error;
982
983   mm->mpls_encap_by_fib_and_dest = hash_create (0, sizeof (uword));
984   mm->mpls_decap_by_rx_fib_and_label = hash_create (0, sizeof (uword));
985
986   return vlib_call_init_function (vm, mpls_input_init);
987 }
988
989 VLIB_INIT_FUNCTION (mpls_init);
990
991 mpls_main_t * mpls_get_main (vlib_main_t * vm)
992 {
993   vlib_call_init_function (vm, mpls_init);
994   return &mpls_main;
995 }
996