d914b4c2b720bc848b5675ed429902faaf084a66
[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 int
581 mpls_dest_cmp(void * a1, void * a2)
582 {
583   show_mpls_fib_t * r1 = a1;
584   show_mpls_fib_t * r2 = a2;
585
586   return clib_net_to_host_u32(r1->dest) - clib_net_to_host_u32(r2->dest);
587 }
588
589 int
590 mpls_fib_index_cmp(void * a1, void * a2)
591 {
592   show_mpls_fib_t * r1 = a1;
593   show_mpls_fib_t * r2 = a2;
594
595   return r1->fib_index - r2->fib_index;
596 }
597
598 int
599 mpls_label_cmp(void * a1, void * a2)
600 {
601   show_mpls_fib_t * r1 = a1;
602   show_mpls_fib_t * r2 = a2;
603
604   return r1->label - r2->label;
605 }
606
607 static clib_error_t *
608 show_mpls_fib_command_fn (vlib_main_t * vm,
609                  unformat_input_t * input,
610                  vlib_cli_command_t * cmd)
611 {
612   u64 key; 
613   u32 value;
614   show_mpls_fib_t *records = 0;
615   show_mpls_fib_t *s;
616   mpls_main_t * mm = &mpls_main;
617   ip4_main_t * im = &ip4_main;
618   ip4_fib_t * rx_fib, * tx_fib;
619   u32 tx_table_id;
620   char *swif_tag;
621
622   hash_foreach (key, value, mm->mpls_encap_by_fib_and_dest, 
623   ({
624     vec_add2 (records, s, 1);
625     s->fib_index = (u32)(key>>32);
626     s->dest = (u32)(key & 0xFFFFFFFF);
627     s->entry_index = (u32) value;
628   }));
629
630   if (!vec_len(records))
631     {
632       vlib_cli_output (vm, "MPLS encap table empty");
633       goto decap_table;
634     }
635   /* sort output by dst address within fib */
636   vec_sort_with_function (records, mpls_dest_cmp);
637   vec_sort_with_function (records, mpls_fib_index_cmp);
638   vlib_cli_output (vm, "MPLS encap table");
639   vlib_cli_output (vm, "%=6s%=16s%=16s", "Table", "Dest address", "Labels");
640   vec_foreach (s, records)
641     {
642       rx_fib = vec_elt_at_index (im->fibs, s->fib_index);
643       vlib_cli_output (vm, "%=6d%=16U%=16U", rx_fib->table_id, 
644                        format_ip4_address, &s->dest,
645                        format_mpls_encap_index, mm, s->entry_index);
646     }
647
648  decap_table:
649   vec_reset_length(records);
650
651   hash_foreach (key, value, mm->mpls_decap_by_rx_fib_and_label, 
652   ({
653     vec_add2 (records, s, 1);
654     s->fib_index = (u32)(key>>32);
655     s->entry_index = (u32) value;
656     s->label = ((u32) key)>>12;
657     s->s_bit = (key & (1<<8)) != 0;
658   }));
659   
660   if (!vec_len(records))
661     {
662       vlib_cli_output (vm, "MPLS decap table empty");
663       goto out;
664     }
665
666   vec_sort_with_function (records, mpls_label_cmp);
667
668   vlib_cli_output (vm, "MPLS decap table");
669   vlib_cli_output (vm, "%=10s%=15s%=6s%=6s", "RX Table", "TX Table/Intfc", 
670                    "Label", "S-bit");
671   vec_foreach (s, records)
672     {
673       mpls_decap_t * d;
674       d = pool_elt_at_index (mm->decaps, s->entry_index);
675       if (d->next_index == MPLS_INPUT_NEXT_IP4_INPUT)
676         {
677           tx_fib = vec_elt_at_index (im->fibs, d->tx_fib_index);
678           tx_table_id = tx_fib->table_id;
679           swif_tag = "     ";
680         }
681       else
682         {
683           tx_table_id = d->tx_fib_index;
684           swif_tag = "(i)  ";
685         }
686       rx_fib = vec_elt_at_index (im->fibs, s->fib_index);
687
688       vlib_cli_output (vm, "%=10d%=10d%=5s%=6d%=6d", rx_fib->table_id, 
689                        tx_table_id, swif_tag, s->label, s->s_bit);
690     }
691
692  out:
693   vec_free(records);
694   return 0;
695 }
696
697 VLIB_CLI_COMMAND (show_mpls_fib_command, static) = {
698     .path = "show mpls fib",
699     .short_help = "show mpls fib",
700     .function = show_mpls_fib_command_fn,
701 };
702
703 int mpls_fib_reset_labels (u32 fib_id)
704 {
705   u64 key; 
706   u32 value;
707   show_mpls_fib_t *records = 0;
708   show_mpls_fib_t *s;
709   mpls_main_t * mm = &mpls_main;
710   ip4_main_t * im = &ip4_main;
711   u32 fib_index;
712   uword *p;
713
714   p = hash_get (im->fib_index_by_table_id, fib_id);
715   if (! p)
716     return VNET_API_ERROR_NO_SUCH_FIB;
717
718   fib_index = p[0];
719
720   hash_foreach (key, value, mm->mpls_encap_by_fib_and_dest, 
721   ({
722     if (fib_index == (u32)(key>>32)) {
723         vec_add2 (records, s, 1);
724         s->dest = (u32)(key & 0xFFFFFFFF);
725         s->entry_index = (u32) value;
726     }
727   }));
728
729   vec_foreach (s, records)
730     {
731       key = ((u64)fib_index<<32) | ((u64) s->dest);
732       hash_unset (mm->mpls_encap_by_fib_and_dest, key);
733       pool_put_index (mm->encaps, s->entry_index);
734     }
735                 
736   vec_reset_length(records);
737
738   hash_foreach (key, value, mm->mpls_decap_by_rx_fib_and_label, 
739   ({
740     if (fib_index == (u32) (key>>32)) {
741         vec_add2 (records, s, 1);
742         s->entry_index = value;
743         s->fib_index = fib_index;
744         s->s_bit = key & (1<<8);
745         s->dest = (u32)((key & 0xFFFFFFFF)>>12);
746     }
747   }));
748   
749   vec_foreach (s, records)
750     {
751        key = ((u64) fib_index <<32) | ((u64) s->dest<<12) |
752         ((u64) s->s_bit);
753       
754       hash_unset (mm->mpls_decap_by_rx_fib_and_label, key);
755       pool_put_index (mm->decaps, s->entry_index);
756     }
757
758   vec_free(records);
759   return 0;
760 }
761
762 static clib_error_t * mpls_init (vlib_main_t * vm)
763 {
764   mpls_main_t * mm = &mpls_main;
765   clib_error_t * error;
766
767   memset (mm, 0, sizeof (mm[0]));
768   mm->vlib_main = vm;
769   mm->vnet_main = vnet_get_main();
770
771   if ((error = vlib_call_init_function (vm, ip_main_init)))
772     return error;
773
774   mm->mpls_encap_by_fib_and_dest = hash_create (0, sizeof (uword));
775   mm->mpls_decap_by_rx_fib_and_label = hash_create (0, sizeof (uword));
776
777   return vlib_call_init_function (vm, mpls_input_init);
778 }
779
780 VLIB_INIT_FUNCTION (mpls_init);
781
782 mpls_main_t * mpls_get_main (vlib_main_t * vm)
783 {
784   vlib_call_init_function (vm, mpls_init);
785   return &mpls_main;
786 }
787