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