Add clib_memcpy macro based on DPDK rte_memcpy implementation
[vpp.git] / vnet / vnet / mpls-gre / 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-gre/mpls.h>
20
21 mpls_main_t mpls_main;
22
23 u8 * format_mpls_gre_tx_trace (u8 * s, va_list * args)
24 {
25   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
26   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
27   mpls_gre_tx_trace_t * t = va_arg (*args, mpls_gre_tx_trace_t *);
28   mpls_main_t * mm = &mpls_main;
29     
30   if (t->lookup_miss)
31     s = format (s, "MPLS: lookup miss");
32   else
33     {
34       s = format (s, "MPLS: tunnel %d labels %U len %d src %U dst %U",
35                   t->tunnel_id,
36                   format_mpls_encap_index, mm, t->mpls_encap_index, 
37                   clib_net_to_host_u16 (t->length),
38                   format_ip4_address, &t->src.as_u8,
39                   format_ip4_address, &t->dst.as_u8);
40     }
41   return s;
42 }
43
44 u8 * format_mpls_eth_tx_trace (u8 * s, va_list * args)
45 {
46   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
47   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
48   mpls_eth_tx_trace_t * t = va_arg (*args, mpls_eth_tx_trace_t *);
49   mpls_main_t * mm = &mpls_main;
50     
51   if (t->lookup_miss)
52     s = format (s, "MPLS: lookup miss");
53   else
54     {
55       s = format (s, "MPLS: tunnel %d labels %U len %d tx_sw_index %d dst %U",
56                   t->tunnel_id,
57                   format_mpls_encap_index, mm, t->mpls_encap_index, 
58                   clib_net_to_host_u16 (t->length),
59                   t->tx_sw_if_index, 
60                   format_ethernet_address, t->dst);
61     }
62   return s;
63 }
64
65 u8 * format_mpls_eth_header_with_length (u8 * s, va_list * args)
66 {
67   ethernet_header_t * h = va_arg (*args, ethernet_header_t *);
68   mpls_unicast_header_t * m = (mpls_unicast_header_t *)(h+1);
69   u32 max_header_bytes = va_arg (*args, u32);
70   uword header_bytes;
71
72   header_bytes = sizeof (h[0]);
73   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
74     return format (s, "ethernet header truncated");
75
76   s = format 
77     (s, "ETHERNET-MPLS label %d", 
78      vnet_mpls_uc_get_label (clib_net_to_host_u32 (m->label_exp_s_ttl)));
79
80   return s;
81 }
82
83 u8 * format_mpls_gre_header_with_length (u8 * s, va_list * args)
84 {
85   gre_header_t * h = va_arg (*args, gre_header_t *);
86   mpls_unicast_header_t * m = (mpls_unicast_header_t *)(h+1);
87   u32 max_header_bytes = va_arg (*args, u32);
88   uword header_bytes;
89
90   header_bytes = sizeof (h[0]);
91   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
92     return format (s, "gre header truncated");
93
94   s = format 
95     (s, "GRE-MPLS label %d", 
96      vnet_mpls_uc_get_label (clib_net_to_host_u32 (m->label_exp_s_ttl)));
97
98   return s;
99 }
100
101 u8 * format_mpls_gre_header (u8 * s, va_list * args)
102 {
103   gre_header_t * h = va_arg (*args, gre_header_t *);
104   return format (s, "%U", format_mpls_gre_header_with_length, h, 0);
105 }
106
107 uword
108 unformat_mpls_gre_header (unformat_input_t * input, va_list * args)
109 {
110   u8 ** result = va_arg (*args, u8 **);
111   gre_header_t _g, * g = &_g;
112   mpls_unicast_header_t _h, * h = &_h;
113   u32 label, label_exp_s_ttl;
114   
115   if (! unformat (input, "MPLS %d", &label))
116     return 0;
117
118   g->protocol = clib_host_to_net_u16 (GRE_PROTOCOL_mpls_unicast);
119
120   label_exp_s_ttl = (label<<12) | (1<<8) /* s-bit */ | 0xFF;
121   h->label_exp_s_ttl = clib_host_to_net_u32 (label_exp_s_ttl);
122
123   /* Add gre, mpls headers to result. */
124   {
125     void * p;
126     u32 g_n_bytes = sizeof (g[0]);
127     u32 h_n_bytes = sizeof (h[0]);
128
129     vec_add2 (*result, p, g_n_bytes);
130     clib_memcpy (p, g, g_n_bytes);
131
132     vec_add2 (*result, p, h_n_bytes);
133     clib_memcpy (p, h, h_n_bytes);
134   }
135   
136   return 1;
137 }
138
139 uword
140 unformat_mpls_label_net_byte_order (unformat_input_t * input,
141                                         va_list * args)
142 {
143   u32 * result = va_arg (*args, u32 *);
144   u32 label;
145
146   if (!unformat (input, "MPLS: label %d", &label))
147     return 0;
148
149   label = (label<<12) | (1<<8) /* s-bit set */ | 0xFF /* ttl */;
150
151   *result = clib_host_to_net_u32 (label);
152   return 1;
153 }
154
155 mpls_encap_t * 
156 mpls_encap_by_fib_and_dest (mpls_main_t * mm, u32 rx_fib, u32 dst_address)
157 {
158   uword * p;
159   mpls_encap_t * e;
160   u64 key;
161
162   key = ((u64)rx_fib<<32) | ((u64) dst_address);
163   p = hash_get (mm->mpls_encap_by_fib_and_dest, key);
164
165   if (!p)
166     return 0;
167
168   e = pool_elt_at_index (mm->encaps, p[0]);
169   return e;
170 }
171
172 int vnet_mpls_add_del_encap (ip4_address_t *dest, u32 fib_id, 
173                              u32 *labels_host_byte_order,
174                              u32 policy_tunnel_index,
175                              int no_dst_hash, u32 * indexp, int is_add)
176 {
177   mpls_main_t * mm = &mpls_main;
178   ip4_main_t * im = &ip4_main;
179   mpls_encap_t * e;
180   u32 label_net_byte_order, label_host_byte_order;
181   u32 fib_index;
182   u64 key;
183   uword *p;
184   int i;
185   
186   p = hash_get (im->fib_index_by_table_id, fib_id);
187   if (! p)
188     return VNET_API_ERROR_NO_SUCH_FIB;
189   
190   fib_index = p[0];
191   
192   key = ((u64)fib_index<<32) | ((u64) dest->as_u32);
193   
194   if (is_add)
195     {
196       pool_get (mm->encaps, e);
197       memset (e, 0, sizeof (*e));
198       
199       for (i = 0; i < vec_len (labels_host_byte_order); i++)
200         {
201           mpls_unicast_header_t h;
202           label_host_byte_order = labels_host_byte_order[i];
203           
204           /* Reformat label into mpls_unicast_header_t */
205           label_host_byte_order <<= 12;
206           if (i == vec_len(labels_host_byte_order) - 1)
207             label_host_byte_order |= 1<<8;            /* S=1 */
208           label_host_byte_order |= 0xff;            /* TTL=FF */
209           label_net_byte_order = clib_host_to_net_u32 (label_host_byte_order);
210           h.label_exp_s_ttl = label_net_byte_order;
211           vec_add1 (e->labels, h);
212         }
213       if (no_dst_hash == 0)
214         hash_set (mm->mpls_encap_by_fib_and_dest, key, e - mm->encaps);
215       if (indexp)
216         *indexp = e - mm->encaps;
217       if (policy_tunnel_index != ~0)
218         return vnet_mpls_policy_tunnel_add_rewrite (mm, e, policy_tunnel_index);
219     }
220   else
221     {
222       p = hash_get (mm->mpls_encap_by_fib_and_dest, key);
223       if (!p)
224         return VNET_API_ERROR_NO_SUCH_LABEL;
225       
226       e = pool_elt_at_index (mm->encaps, p[0]);
227       
228       vec_free (e->labels);
229       vec_free (e->rewrite);
230       pool_put(mm->encaps, e);
231       
232       if (no_dst_hash == 0)
233         hash_unset (mm->mpls_encap_by_fib_and_dest, key);    
234     }
235   return 0;
236 }
237
238 static clib_error_t *
239 mpls_add_encap_command_fn (vlib_main_t * vm,
240                            unformat_input_t * input,
241                            vlib_cli_command_t * cmd)
242 {
243   u32 fib_id;
244   u32 *labels = 0;
245   u32 this_label;
246   ip4_address_t dest;
247   u32 policy_tunnel_index = ~0;
248   int no_dst_hash = 0;
249   int rv;
250   int fib_set = 0;
251   int dest_set = 0;
252
253   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
254     {
255       if (unformat (input, "fib %d", &fib_id))
256         fib_set = 1;
257       else if (unformat (input, "dest %U", unformat_ip4_address, &dest))
258         dest_set = 1;
259       else if (unformat (input, "no-dst-hash"))
260         no_dst_hash = 1;
261       else if (unformat (input, "label %d", &this_label))
262         vec_add1 (labels, this_label);
263       else if (unformat (input, "policy-tunnel %d", &policy_tunnel_index))
264         ;
265       else
266         break;
267     }
268
269   if (fib_set == 0)
270     return clib_error_return (0, "fib-id missing");
271   if (dest_set == 0)
272     return clib_error_return (0, "destination IP address missing");
273   if (vec_len (labels) == 0)
274     return clib_error_return (0, "label stack missing");
275   
276   rv = vnet_mpls_add_del_encap (&dest, fib_id, labels, 
277                                 policy_tunnel_index, 
278                                 no_dst_hash, 0 /* indexp */,
279                                 1 /* is_add */);
280   vec_free (labels);
281
282   switch (rv)
283     {
284     case 0:
285       break;
286
287     case VNET_API_ERROR_NO_SUCH_FIB:
288       return clib_error_return (0, "fib id %d unknown", fib_id);
289       
290     default:
291       return clib_error_return (0, "vnet_mpls_add_del_encap returned %d", 
292                                 rv);
293     }
294
295   return 0;
296 }
297
298 VLIB_CLI_COMMAND (mpls_add_encap_command, static) = {
299   .path = "mpls encap add",
300   .short_help = 
301   "mpls encap add label <label> ... fib <id> dest <ip4-address>",
302   .function = mpls_add_encap_command_fn,
303 };
304
305 u8 * format_mpls_unicast_header_host_byte_order (u8 * s, va_list * args)
306 {
307   mpls_unicast_header_t *h = va_arg(*args, mpls_unicast_header_t *);
308   u32 label = h->label_exp_s_ttl;
309   
310   s = format (s, "label %d exp %d, s %d, ttl %d",
311               vnet_mpls_uc_get_label (label),
312               vnet_mpls_uc_get_exp (label),
313               vnet_mpls_uc_get_s (label),
314               vnet_mpls_uc_get_ttl (label));
315   return s;
316 }
317
318 u8 * format_mpls_unicast_header_net_byte_order (u8 * s, va_list * args)
319 {
320   mpls_unicast_header_t *h = va_arg(*args, mpls_unicast_header_t *);
321   mpls_unicast_header_t h_host;
322
323   h_host.label_exp_s_ttl = clib_net_to_host_u32 (h->label_exp_s_ttl);
324
325   return format (s, "%U", format_mpls_unicast_header_host_byte_order,
326                  &h_host);
327 }
328
329 static clib_error_t *
330 mpls_del_encap_command_fn (vlib_main_t * vm,
331                  unformat_input_t * input,
332                  vlib_cli_command_t * cmd)
333 {
334   u32 fib_id;
335   ip4_address_t dest;
336   int rv;
337   
338   if (unformat (input, "fib %d dest %U", &fib_id, 
339                 unformat_ip4_address, &dest)) 
340     {
341       rv = vnet_mpls_add_del_encap (&dest, fib_id, 0 /* labels */, 
342                                     ~0 /* policy_tunnel_index */,
343                                     0 /* no_dst_hash */,
344                                     0 /* indexp */,
345                                     0 /* is_add */);
346       switch (rv)
347         {
348         case VNET_API_ERROR_NO_SUCH_FIB:
349           return clib_error_return (0, "fib id %d unknown", fib_id);
350         case VNET_API_ERROR_NO_SUCH_ENTRY:
351           return clib_error_return (0, "dest %U not in fib %d",
352                                     format_ip4_address, &dest, fib_id);
353         default:
354           break;
355         }
356       return 0;
357     }
358   else
359     return clib_error_return (0, "unknown input `%U'",
360                               format_unformat_error, input);
361 }
362
363 VLIB_CLI_COMMAND (mpls_del_encap_command, static) = {
364   .path = "mpls encap delete",
365   .short_help = "mpls encap delete fib <id> dest <ip4-address>",
366   .function = mpls_del_encap_command_fn,
367 };
368
369 int vnet_mpls_add_del_decap (u32 rx_fib_id, 
370                              u32 tx_fib_id,
371                              u32 label_host_byte_order, 
372                              int s_bit, int next_index, int is_add)
373 {
374   mpls_main_t * mm = &mpls_main;
375   ip4_main_t * im = &ip4_main;
376   mpls_decap_t * d;
377   u32 rx_fib_index, tx_fib_index_or_output_swif_index;
378   uword *p;
379   u64 key;
380   
381   p = hash_get (im->fib_index_by_table_id, rx_fib_id);
382   if (! p)
383     return VNET_API_ERROR_NO_SUCH_FIB;
384
385   rx_fib_index = p[0];
386
387   /* L3 decap => transform fib ID to fib index */
388   if (next_index == MPLS_INPUT_NEXT_IP4_INPUT)
389     {
390       p = hash_get (im->fib_index_by_table_id, tx_fib_id);
391       if (! p)
392         return VNET_API_ERROR_NO_SUCH_INNER_FIB;
393       
394       tx_fib_index_or_output_swif_index = p[0];
395     }
396   else
397     {
398       /* L2 decap, tx_fib_id is actually the output sw_if_index */
399       tx_fib_index_or_output_swif_index = tx_fib_id;
400     }
401
402   key = ((u64)rx_fib_index<<32) | ((u64) (label_host_byte_order<<12))
403     | ((u64) s_bit<<8);
404
405   p = hash_get (mm->mpls_decap_by_rx_fib_and_label, key);
406
407   /* If deleting, or replacing an old entry */
408   if (is_add == 0 || p)
409     {
410       if (is_add == 0 && p == 0)
411         return VNET_API_ERROR_NO_SUCH_LABEL;
412
413       d = pool_elt_at_index (mm->decaps, p[0]);
414       hash_unset (mm->mpls_decap_by_rx_fib_and_label, key);
415       pool_put (mm->decaps, d);
416       /* Deleting, we're done... */
417       if (is_add == 0)
418         return 0;
419     }
420
421   /* add decap entry... */
422   pool_get (mm->decaps, d);
423   memset (d, 0, sizeof (*d));
424   d->tx_fib_index = tx_fib_index_or_output_swif_index;
425   d->next_index = next_index;
426
427   hash_set (mm->mpls_decap_by_rx_fib_and_label, key, d - mm->decaps);
428
429   return 0;
430 }
431
432 uword
433 unformat_mpls_gre_input_next (unformat_input_t * input, va_list * args)
434 {
435   u32 * result = va_arg (*args, u32 *);
436   int rv = 0;
437
438   if (unformat (input, "lookup"))
439     {
440       *result = MPLS_INPUT_NEXT_IP4_INPUT;
441       rv = 1;
442     }
443   else if (unformat (input, "output"))
444     {
445       *result = MPLS_INPUT_NEXT_L2_OUTPUT;
446       rv = 1;
447     }
448   return rv;
449 }
450
451 static clib_error_t *
452 mpls_add_decap_command_fn (vlib_main_t * vm,
453                            unformat_input_t * input,
454                            vlib_cli_command_t * cmd)
455 {
456   vnet_main_t * vnm = vnet_get_main();
457   u32 rx_fib_id = 0;
458   u32 tx_fib_or_sw_if_index;
459   u32 label;
460   int s_bit = 1;
461   u32 next_index = 1;           /* ip4_lookup, see node.c */
462   int tx_fib_id_set = 0;
463   int label_set = 0;
464   int rv;
465
466   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
467     {
468       if (unformat (input, "fib %d", &tx_fib_or_sw_if_index))
469         tx_fib_id_set = 1;
470       else if (unformat (input, "sw_if_index %d", &tx_fib_or_sw_if_index))
471         tx_fib_id_set = 1;
472       else if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
473                          &tx_fib_or_sw_if_index))
474         tx_fib_id_set = 1;
475       else if (unformat (input, "rx-fib %d", &rx_fib_id))
476         ;
477       else if (unformat (input, "label %d", &label))
478         label_set = 1;
479       else if (unformat (input, "s-bit-clear"))
480         s_bit = 0;
481       else if (unformat (input, "next %U", unformat_mpls_gre_input_next, 
482                          &next_index))
483         ;
484       else
485         break;
486     }
487
488   if (tx_fib_id_set == 0)
489     return clib_error_return (0, "lookup FIB ID not set");
490   if (label_set == 0)
491     return clib_error_return (0, "missing label");
492   
493   rv = vnet_mpls_add_del_decap (rx_fib_id, tx_fib_or_sw_if_index, 
494                                 label, s_bit, next_index, 1 /* is_add */);
495   switch (rv)
496     {
497     case 0:
498       break;
499
500     case VNET_API_ERROR_NO_SUCH_FIB:
501       return clib_error_return (0, "no such rx fib id %d", rx_fib_id);
502
503     case VNET_API_ERROR_NO_SUCH_INNER_FIB:
504       return clib_error_return (0, "no such tx fib / swif %d", 
505                                 tx_fib_or_sw_if_index);
506
507     default:
508       return clib_error_return (0, "vnet_mpls_add_del_decap returned %d",
509                                 rv);
510     }
511   return 0;
512 }
513
514 VLIB_CLI_COMMAND (mpls_add_decap_command, static) = {
515     .path = "mpls decap add",
516     .short_help = 
517     "mpls decap add fib <id> label <nn> [s-bit-clear] [next-index <nn>]",
518     .function = mpls_add_decap_command_fn, 
519 };
520
521 static clib_error_t *
522 mpls_del_decap_command_fn (vlib_main_t * vm,
523                            unformat_input_t * input,
524                            vlib_cli_command_t * cmd)
525 {
526   u32 rx_fib_id = 0;
527   u32 tx_fib_id = 0;
528   u32 label;
529   int s_bit = 1;
530   int label_set = 0;
531   int rv;
532
533   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
534     {
535       if (unformat (input, "rx-fib %d", &rx_fib_id))
536         ;
537       else if (unformat (input, "label %d", &label))
538         label_set = 1;
539       else if (unformat (input, "s-bit-clear"))
540         s_bit = 0;
541     }
542
543   if (!label_set)
544     return clib_error_return (0, "label not set");
545
546   rv = vnet_mpls_add_del_decap (rx_fib_id, 
547                                 tx_fib_id /* not interesting */,
548                                 label, s_bit, 
549                                 0 /* next_index not interesting */,
550                                 0 /* is_add */);
551   switch (rv)
552     {
553     case 0:
554       break;
555
556     case VNET_API_ERROR_NO_SUCH_FIB:
557       return clib_error_return (0, "no such rx fib id %d", rx_fib_id);
558
559     case VNET_API_ERROR_NO_SUCH_INNER_FIB:
560       return clib_error_return (0, "no such lookup fib id %d", tx_fib_id);
561
562     case VNET_API_ERROR_NO_SUCH_LABEL:
563       return clib_error_return (0, "no such label %d rx fib id %d", 
564                                 label, rx_fib_id);
565
566     default:
567       return clib_error_return (0, "vnet_mpls_add_del_decap returned %d",
568                                 rv);
569     }
570   return 0;
571 }
572
573
574 VLIB_CLI_COMMAND (mpls_del_decap_command, static) = {
575   .path = "mpls decap delete",
576   .short_help = "mpls decap delete label <label> rx-fib <id> [s-bit-clear]",
577   .function = mpls_del_decap_command_fn,
578 };
579
580 typedef struct {
581   u32 fib_index;
582   u32 entry_index;
583   u32 dest;
584   u32 s_bit;
585   u32 label;
586 } show_mpls_fib_t;
587
588 static int
589 mpls_dest_cmp(void * a1, void * a2)
590 {
591   show_mpls_fib_t * r1 = a1;
592   show_mpls_fib_t * r2 = a2;
593
594   return clib_net_to_host_u32(r1->dest) - clib_net_to_host_u32(r2->dest);
595 }
596
597 static int
598 mpls_fib_index_cmp(void * a1, void * a2)
599 {
600   show_mpls_fib_t * r1 = a1;
601   show_mpls_fib_t * r2 = a2;
602
603   return r1->fib_index - r2->fib_index;
604 }
605
606 static int
607 mpls_label_cmp(void * a1, void * a2)
608 {
609   show_mpls_fib_t * r1 = a1;
610   show_mpls_fib_t * r2 = a2;
611
612   return r1->label - r2->label;
613 }
614
615 static clib_error_t *
616 show_mpls_fib_command_fn (vlib_main_t * vm,
617                  unformat_input_t * input,
618                  vlib_cli_command_t * cmd)
619 {
620   u64 key; 
621   u32 value;
622   show_mpls_fib_t *records = 0;
623   show_mpls_fib_t *s;
624   mpls_main_t * mm = &mpls_main;
625   ip4_main_t * im = &ip4_main;
626   ip4_fib_t * rx_fib, * tx_fib;
627   u32 tx_table_id;
628   char *swif_tag;
629
630   hash_foreach (key, value, mm->mpls_encap_by_fib_and_dest, 
631   ({
632     vec_add2 (records, s, 1);
633     s->fib_index = (u32)(key>>32);
634     s->dest = (u32)(key & 0xFFFFFFFF);
635     s->entry_index = (u32) value;
636   }));
637
638   if (!vec_len(records))
639     {
640       vlib_cli_output (vm, "MPLS encap table empty");
641       goto decap_table;
642     }
643   /* sort output by dst address within fib */
644   vec_sort_with_function (records, mpls_dest_cmp);
645   vec_sort_with_function (records, mpls_fib_index_cmp);
646   vlib_cli_output (vm, "MPLS encap table");
647   vlib_cli_output (vm, "%=6s%=16s%=16s", "Table", "Dest address", "Labels");
648   vec_foreach (s, records)
649     {
650       rx_fib = vec_elt_at_index (im->fibs, s->fib_index);
651       vlib_cli_output (vm, "%=6d%=16U%=16U", rx_fib->table_id, 
652                        format_ip4_address, &s->dest,
653                        format_mpls_encap_index, mm, s->entry_index);
654     }
655
656  decap_table:
657   vec_reset_length(records);
658
659   hash_foreach (key, value, mm->mpls_decap_by_rx_fib_and_label, 
660   ({
661     vec_add2 (records, s, 1);
662     s->fib_index = (u32)(key>>32);
663     s->entry_index = (u32) value;
664     s->label = ((u32) key)>>12;
665     s->s_bit = (key & (1<<8)) != 0;
666   }));
667   
668   if (!vec_len(records))
669     {
670       vlib_cli_output (vm, "MPLS decap table empty");
671       goto out;
672     }
673
674   vec_sort_with_function (records, mpls_label_cmp);
675
676   vlib_cli_output (vm, "MPLS decap table");
677   vlib_cli_output (vm, "%=10s%=15s%=6s%=6s", "RX Table", "TX Table/Intfc", 
678                    "Label", "S-bit");
679   vec_foreach (s, records)
680     {
681       mpls_decap_t * d;
682       d = pool_elt_at_index (mm->decaps, s->entry_index);
683       if (d->next_index == MPLS_INPUT_NEXT_IP4_INPUT)
684         {
685           tx_fib = vec_elt_at_index (im->fibs, d->tx_fib_index);
686           tx_table_id = tx_fib->table_id;
687           swif_tag = "     ";
688         }
689       else
690         {
691           tx_table_id = d->tx_fib_index;
692           swif_tag = "(i)  ";
693         }
694       rx_fib = vec_elt_at_index (im->fibs, s->fib_index);
695
696       vlib_cli_output (vm, "%=10d%=10d%=5s%=6d%=6d", rx_fib->table_id, 
697                        tx_table_id, swif_tag, s->label, s->s_bit);
698     }
699
700  out:
701   vec_free(records);
702   return 0;
703 }
704
705 VLIB_CLI_COMMAND (show_mpls_fib_command, static) = {
706     .path = "show mpls fib",
707     .short_help = "show mpls fib",
708     .function = show_mpls_fib_command_fn,
709 };
710
711 int mpls_fib_reset_labels (u32 fib_id)
712 {
713   u64 key; 
714   u32 value;
715   show_mpls_fib_t *records = 0;
716   show_mpls_fib_t *s;
717   mpls_main_t * mm = &mpls_main;
718   ip4_main_t * im = &ip4_main;
719   u32 fib_index;
720   uword *p;
721
722   p = hash_get (im->fib_index_by_table_id, fib_id);
723   if (! p)
724     return VNET_API_ERROR_NO_SUCH_FIB;
725
726   fib_index = p[0];
727
728   hash_foreach (key, value, mm->mpls_encap_by_fib_and_dest, 
729   ({
730     if (fib_index == (u32)(key>>32)) {
731         vec_add2 (records, s, 1);
732         s->dest = (u32)(key & 0xFFFFFFFF);
733         s->entry_index = (u32) value;
734     }
735   }));
736
737   vec_foreach (s, records)
738     {
739       key = ((u64)fib_index<<32) | ((u64) s->dest);
740       hash_unset (mm->mpls_encap_by_fib_and_dest, key);
741       pool_put_index (mm->encaps, s->entry_index);
742     }
743                 
744   vec_reset_length(records);
745
746   hash_foreach (key, value, mm->mpls_decap_by_rx_fib_and_label, 
747   ({
748     if (fib_index == (u32) (key>>32)) {
749         vec_add2 (records, s, 1);
750         s->entry_index = value;
751         s->fib_index = fib_index;
752         s->s_bit = key & (1<<8);
753         s->dest = (u32)((key & 0xFFFFFFFF)>>12);
754     }
755   }));
756   
757   vec_foreach (s, records)
758     {
759       key = ((u64)fib_index <<32) | ((u64)(s->dest<<12)) |
760         ((u64)s->s_bit);
761       
762       hash_unset (mm->mpls_decap_by_rx_fib_and_label, key);
763       pool_put_index (mm->decaps, s->entry_index);
764     }
765
766   vec_free(records);
767   return 0;
768 }
769
770 static clib_error_t * mpls_init (vlib_main_t * vm)
771 {
772   mpls_main_t * mm = &mpls_main;
773   clib_error_t * error;
774
775   memset (mm, 0, sizeof (mm[0]));
776   mm->vlib_main = vm;
777   mm->vnet_main = vnet_get_main();
778
779   if ((error = vlib_call_init_function (vm, ip_main_init)))
780     return error;
781
782   mm->mpls_encap_by_fib_and_dest = hash_create (0, sizeof (uword));
783   mm->mpls_decap_by_rx_fib_and_label = hash_create (0, sizeof (uword));
784
785   return vlib_call_init_function (vm, mpls_input_init);
786 }
787
788 VLIB_INIT_FUNCTION (mpls_init);
789
790 mpls_main_t * mpls_get_main (vlib_main_t * vm)
791 {
792   vlib_call_init_function (vm, mpls_init);
793   return &mpls_main;
794 }
795