54bc8081993a4ebb548237e92c6ee87992be5516
[vpp.git] / vnet / vnet / fib / fib_table.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vlib/vlib.h>
17 #include <vnet/dpo/drop_dpo.h>
18
19 #include <vnet/fib/fib_table.h>
20 #include <vnet/fib/fib_entry_cover.h>
21 #include <vnet/fib/fib_internal.h>
22 #include <vnet/fib/ip4_fib.h>
23 #include <vnet/fib/ip6_fib.h>
24 #include <vnet/fib/mpls_fib.h>
25
26 fib_table_t *
27 fib_table_get (fib_node_index_t index,
28                fib_protocol_t proto)
29 {
30     switch (proto)
31     {
32     case FIB_PROTOCOL_IP4:
33         return (pool_elt_at_index(ip4_main.fibs, index));
34     case FIB_PROTOCOL_IP6:
35         return (pool_elt_at_index(ip6_main.fibs, index));
36     case FIB_PROTOCOL_MPLS:
37         return (pool_elt_at_index(mpls_main.fibs, index));
38     }
39     ASSERT(0);
40     return (NULL);
41 }
42
43 static inline fib_node_index_t
44 fib_table_lookup_i (fib_table_t *fib_table,
45                     const fib_prefix_t *prefix)
46 {
47     switch (prefix->fp_proto)
48     {
49     case FIB_PROTOCOL_IP4:
50         return (ip4_fib_table_lookup(&fib_table->v4,
51                                      &prefix->fp_addr.ip4,
52                                      prefix->fp_len));
53     case FIB_PROTOCOL_IP6:
54         return (ip6_fib_table_lookup(fib_table->ft_index,
55                                      &prefix->fp_addr.ip6,
56                                      prefix->fp_len));
57     case FIB_PROTOCOL_MPLS:
58         return (mpls_fib_table_lookup(&fib_table->mpls,
59                                       prefix->fp_label,
60                                       prefix->fp_eos));
61     }
62     return (FIB_NODE_INDEX_INVALID);
63 }
64
65 fib_node_index_t
66 fib_table_lookup (u32 fib_index,
67                   const fib_prefix_t *prefix)
68 {
69     return (fib_table_lookup_i(fib_table_get(fib_index, prefix->fp_proto), prefix));
70 }
71
72 static inline fib_node_index_t
73 fib_table_lookup_exact_match_i (const fib_table_t *fib_table,
74                                 const fib_prefix_t *prefix)
75 {
76     switch (prefix->fp_proto)
77     {
78     case FIB_PROTOCOL_IP4:
79         return (ip4_fib_table_lookup_exact_match(&fib_table->v4,
80                                                  &prefix->fp_addr.ip4,
81                                                  prefix->fp_len));
82     case FIB_PROTOCOL_IP6:
83         return (ip6_fib_table_lookup_exact_match(fib_table->ft_index,
84                                                  &prefix->fp_addr.ip6,
85                                                  prefix->fp_len));
86     case FIB_PROTOCOL_MPLS:
87         return (mpls_fib_table_lookup(&fib_table->mpls,
88                                       prefix->fp_label,
89                                       prefix->fp_eos));
90     }
91     return (FIB_NODE_INDEX_INVALID);
92 }
93
94 fib_node_index_t
95 fib_table_lookup_exact_match (u32 fib_index,
96                               const fib_prefix_t *prefix)
97 {
98     return (fib_table_lookup_exact_match_i(fib_table_get(fib_index,
99                                                          prefix->fp_proto),
100                                            prefix));
101 }
102
103 static fib_node_index_t
104 fib_table_get_less_specific_i (fib_table_t *fib_table,
105                                const fib_prefix_t *prefix)
106 {
107     fib_prefix_t pfx;
108
109     pfx = *prefix;
110
111     if (FIB_PROTOCOL_MPLS == pfx.fp_proto)
112     {
113         return (FIB_NODE_INDEX_INVALID);
114     }
115
116     /*
117      * in the absence of a tree structure for the table that allows for an O(1)
118      * parent get, a cheeky way to find the cover is to LPM for the prefix with
119      * mask-1.
120      * there should always be a cover, though it may be the default route. the
121      * default route's cover is the default route.
122      */
123     if (pfx.fp_len != 0) {
124         pfx.fp_len -= 1;
125     }
126
127     return (fib_table_lookup_i(fib_table, &pfx));    
128 }
129
130 fib_node_index_t
131 fib_table_get_less_specific (u32 fib_index,
132                              const fib_prefix_t *prefix)
133 {
134     return (fib_table_get_less_specific_i(fib_table_get(fib_index,
135                                                         prefix->fp_proto),
136                                           prefix));
137 }
138
139 static void
140 fib_table_entry_remove (fib_table_t *fib_table,
141                         const fib_prefix_t *prefix,
142                         fib_node_index_t fib_entry_index)
143 {
144     vlib_smp_unsafe_warning();
145
146     fib_table->ft_total_route_counts--;
147
148     switch (prefix->fp_proto)
149     {
150     case FIB_PROTOCOL_IP4:
151         ip4_fib_table_entry_remove(&fib_table->v4,
152                                    &prefix->fp_addr.ip4,
153                                    prefix->fp_len);
154         break;
155     case FIB_PROTOCOL_IP6:
156         ip6_fib_table_entry_remove(fib_table->ft_index,
157                                    &prefix->fp_addr.ip6,
158                                    prefix->fp_len);
159         break;
160     case FIB_PROTOCOL_MPLS:
161         mpls_fib_table_entry_remove(&fib_table->mpls,
162                                     prefix->fp_label,
163                                     prefix->fp_eos);
164         break;
165     }
166
167     fib_entry_unlock(fib_entry_index);
168 }
169
170 static void
171 fib_table_post_insert_actions (fib_table_t *fib_table,
172                                const fib_prefix_t *prefix,
173                                fib_node_index_t fib_entry_index)
174 {
175     fib_node_index_t fib_entry_cover_index;
176
177     /*
178      * no cover relationships in the MPLS FIB
179      */
180     if (FIB_PROTOCOL_MPLS == prefix->fp_proto)
181         return;
182
183     /*
184      * find and inform the covering entry that a new more specific
185      * has been inserted beneath it
186      */
187     fib_entry_cover_index = fib_table_get_less_specific_i(fib_table, prefix);
188     /*
189      * the indicies are the same when the default route is first added
190      */
191     if (fib_entry_cover_index != fib_entry_index)
192     {
193         fib_entry_cover_change_notify(fib_entry_cover_index,
194                                       fib_entry_index);
195     }
196 }
197
198 static void
199 fib_table_entry_insert (fib_table_t *fib_table,
200                         const fib_prefix_t *prefix,
201                         fib_node_index_t fib_entry_index)
202 {
203     vlib_smp_unsafe_warning();
204
205     fib_entry_lock(fib_entry_index);
206     fib_table->ft_total_route_counts++;
207
208     switch (prefix->fp_proto)
209     {
210     case FIB_PROTOCOL_IP4:
211         ip4_fib_table_entry_insert(&fib_table->v4,
212                                    &prefix->fp_addr.ip4,
213                                    prefix->fp_len,
214                                    fib_entry_index);
215         break;
216     case FIB_PROTOCOL_IP6:
217         ip6_fib_table_entry_insert(fib_table->ft_index,
218                                    &prefix->fp_addr.ip6,
219                                    prefix->fp_len,
220                                    fib_entry_index);
221         break;
222     case FIB_PROTOCOL_MPLS:
223         mpls_fib_table_entry_insert(&fib_table->mpls,
224                                     prefix->fp_label,
225                                     prefix->fp_eos,
226                                     fib_entry_index);
227         break;
228     }
229
230     fib_table_post_insert_actions(fib_table, prefix, fib_entry_index);
231 }
232
233 void
234 fib_table_fwding_dpo_update (u32 fib_index,
235                              const fib_prefix_t *prefix,
236                              const dpo_id_t *dpo)
237 {
238     vlib_smp_unsafe_warning();
239
240     switch (prefix->fp_proto)
241     {
242     case FIB_PROTOCOL_IP4:
243         return (ip4_fib_table_fwding_dpo_update(ip4_fib_get(fib_index),
244                                                 &prefix->fp_addr.ip4,
245                                                 prefix->fp_len,
246                                                 dpo));
247     case FIB_PROTOCOL_IP6:
248         return (ip6_fib_table_fwding_dpo_update(fib_index,
249                                                 &prefix->fp_addr.ip6,
250                                                 prefix->fp_len,
251                                                 dpo));
252     case FIB_PROTOCOL_MPLS:
253         return (mpls_fib_forwarding_table_update(mpls_fib_get(fib_index),
254                                                  prefix->fp_label,
255                                                  prefix->fp_eos,
256                                                  dpo));
257     }
258 }
259
260 void
261 fib_table_fwding_dpo_remove (u32 fib_index,
262                              const fib_prefix_t *prefix,
263                              const dpo_id_t *dpo)
264 {
265     vlib_smp_unsafe_warning();
266
267     switch (prefix->fp_proto)
268     {
269     case FIB_PROTOCOL_IP4:
270         return (ip4_fib_table_fwding_dpo_remove(ip4_fib_get(fib_index),
271                                                 &prefix->fp_addr.ip4,
272                                                 prefix->fp_len,
273                                                 dpo));
274     case FIB_PROTOCOL_IP6:
275         return (ip6_fib_table_fwding_dpo_remove(fib_index,
276                                                 &prefix->fp_addr.ip6,
277                                                 prefix->fp_len,
278                                                 dpo));
279     case FIB_PROTOCOL_MPLS:
280         return (mpls_fib_forwarding_table_reset(mpls_fib_get(fib_index),
281                                                 prefix->fp_label,
282                                                 prefix->fp_eos));
283     }
284 }
285
286
287 fib_node_index_t
288 fib_table_entry_special_dpo_add (u32 fib_index,
289                                  const fib_prefix_t *prefix,
290                                  fib_source_t source,
291                                  fib_entry_flag_t flags,
292                                  const dpo_id_t *dpo)
293 {
294     fib_node_index_t fib_entry_index;
295     fib_table_t *fib_table;
296
297     fib_table = fib_table_get(fib_index, prefix->fp_proto);
298     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
299
300     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
301     {
302         fib_entry_index = fib_entry_create_special(fib_index, prefix,
303                                                    source, flags,
304                                                    dpo);
305
306         fib_table_entry_insert(fib_table, prefix, fib_entry_index);
307         fib_table->ft_src_route_counts[source]++;
308     }
309     else
310     {
311         int was_sourced;
312
313         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
314         fib_entry_special_add(fib_entry_index, source, flags, dpo);
315
316         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
317         {
318             fib_table->ft_src_route_counts[source]++;
319         }
320     }
321
322
323     return (fib_entry_index);
324 }
325
326 fib_node_index_t
327 fib_table_entry_special_dpo_update (u32 fib_index,
328                                     const fib_prefix_t *prefix,
329                                     fib_source_t source,
330                                     fib_entry_flag_t flags,
331                                     const dpo_id_t *dpo)
332 {
333     fib_node_index_t fib_entry_index;
334     fib_table_t *fib_table;
335
336     fib_table = fib_table_get(fib_index, prefix->fp_proto);
337     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
338
339     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
340     {
341         fib_entry_index = fib_entry_create_special(fib_index, prefix,
342                                                    source, flags,
343                                                    dpo);
344
345         fib_table_entry_insert(fib_table, prefix, fib_entry_index);
346         fib_table->ft_src_route_counts[source]++;
347     }
348     else
349     {
350         int was_sourced;
351
352         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
353
354         if (was_sourced)
355             fib_entry_special_update(fib_entry_index, source, flags, dpo);
356         else
357             fib_entry_special_add(fib_entry_index, source, flags, dpo);
358
359         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
360         {
361             fib_table->ft_src_route_counts[source]++;
362         }
363     }
364
365     return (fib_entry_index);
366 }
367
368 fib_node_index_t
369 fib_table_entry_special_add (u32 fib_index,
370                              const fib_prefix_t *prefix,
371                              fib_source_t source,
372                              fib_entry_flag_t flags,
373                              adj_index_t adj_index)
374 {
375     fib_node_index_t fib_entry_index;
376     dpo_id_t tmp_dpo = DPO_INVALID;
377
378     if (ADJ_INDEX_INVALID != adj_index)
379     {
380         dpo_set(&tmp_dpo,
381                 DPO_ADJACENCY,
382                 FIB_PROTOCOL_MAX,
383                 adj_index);
384     }
385     else
386     {
387         dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto)));
388     }
389  
390     fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, source,
391                                                       flags, &tmp_dpo);
392
393     dpo_unlock(&tmp_dpo);
394
395     return (fib_entry_index);
396 }
397
398 void
399 fib_table_entry_special_remove (u32 fib_index,
400                                 const fib_prefix_t *prefix,
401                                 fib_source_t source)
402 {
403     /*
404      * 1 is it present
405      *   yes => remove source
406      *    2 - is it still sourced?
407      *      no => cover walk
408      */
409     fib_node_index_t fib_entry_index;
410     fib_table_t *fib_table;
411
412     fib_table = fib_table_get(fib_index, prefix->fp_proto);
413     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
414
415     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
416     {
417         /*
418          * removing an etry that does not exist. i'll allow it.
419          */
420     }
421     else
422     {
423         fib_entry_src_flag_t src_flag;
424         int was_sourced;
425
426         /*
427          * don't nobody go nowhere
428          */
429         fib_entry_lock(fib_entry_index);
430         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
431
432         src_flag = fib_entry_special_remove(fib_entry_index, source);
433
434         if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
435         {
436             /*
437              * last source gone. remove from the table
438              */
439             fib_table_entry_remove(fib_table, prefix, fib_entry_index);
440
441             /*
442              * now the entry is no longer in the table, we can
443              * inform the entries that it covers to re-calculate their cover
444              */
445             fib_entry_cover_change_notify(fib_entry_index,
446                                           FIB_NODE_INDEX_INVALID);
447         }
448         /*
449          * else
450          *   still has sources, leave it be.
451          */
452         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
453         {
454             fib_table->ft_src_route_counts[source]--;
455         }
456
457         fib_entry_unlock(fib_entry_index);
458     }
459 }
460
461 /**
462  * fib_table_route_path_fixup
463  *
464  * Convert attached hosts to attached next-hops.
465  * 
466  * This special case is required because an attached path will link to a
467  * glean, and the FIB entry will have the interface or API/CLI source. When
468  * the ARP/ND process is completes then that source (which will provide a
469  * complete adjacency) will be lower priority and so the FIB entry will
470  * remain linked to a glean and traffic will never reach the hosts. For
471  * an ATTAHCED_HOST path we can link the path directly to the [incomplete]
472  * adjacency.
473  */
474 static void
475 fib_table_route_path_fixup (const fib_prefix_t *prefix,
476                             fib_route_path_t *path)
477 {
478     if (fib_prefix_is_host(prefix) &&
479         ip46_address_is_zero(&path->frp_addr) &&
480         path->frp_sw_if_index != ~0)
481     {
482         path->frp_addr = prefix->fp_addr;
483     }
484 }                 
485
486 fib_node_index_t
487 fib_table_entry_path_add (u32 fib_index,
488                           const fib_prefix_t *prefix,
489                           fib_source_t source,
490                           fib_entry_flag_t flags,
491                           fib_protocol_t next_hop_proto,
492                           const ip46_address_t *next_hop,
493                           u32 next_hop_sw_if_index,
494                           u32 next_hop_fib_index,
495                           u32 next_hop_weight,
496                           mpls_label_t next_hop_label,
497                           fib_route_path_flags_t path_flags)
498 {
499     fib_route_path_t path = {
500         .frp_proto = next_hop_proto,
501         .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
502         .frp_sw_if_index = next_hop_sw_if_index,
503         .frp_fib_index = next_hop_fib_index,
504         .frp_weight = next_hop_weight,
505         .frp_flags = path_flags,
506         .frp_label = next_hop_label,
507     };
508     fib_node_index_t fib_entry_index;
509     fib_route_path_t *paths = NULL;
510
511     fib_table_route_path_fixup(prefix, &path);
512     vec_add1(paths, path);
513
514     fib_entry_index = fib_table_entry_path_add2(fib_index, prefix,
515                                                 source, flags, paths);
516
517     vec_free(paths);
518     return (fib_entry_index);
519 }
520
521 fib_node_index_t
522 fib_table_entry_path_add2 (u32 fib_index,
523                            const fib_prefix_t *prefix,
524                            fib_source_t source,
525                            fib_entry_flag_t flags,
526                            const fib_route_path_t *rpath)
527 {
528     fib_node_index_t fib_entry_index;
529     fib_table_t *fib_table;
530
531     fib_table = fib_table_get(fib_index, prefix->fp_proto);
532     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
533
534     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
535     {
536         fib_entry_index = fib_entry_create(fib_index, prefix,
537                                            source, flags,
538                                            rpath);
539
540         fib_table_entry_insert(fib_table, prefix, fib_entry_index);
541         fib_table->ft_src_route_counts[source]++;
542     }
543     else
544     {
545         int was_sourced;
546
547         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
548         fib_entry_path_add(fib_entry_index, source, flags, rpath);;
549
550         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
551         {
552             fib_table->ft_src_route_counts[source]++;
553         }
554     }
555
556     return (fib_entry_index);
557 }
558
559 void
560 fib_table_entry_path_remove2 (u32 fib_index,
561                              const fib_prefix_t *prefix,
562                              fib_source_t source,
563                               const fib_route_path_t *rpath)
564 {
565     /*
566      * 1 is it present
567      *   yes => remove source
568      *    2 - is it still sourced?
569      *      no => cover walk
570      */
571     fib_node_index_t fib_entry_index;
572     fib_table_t *fib_table;
573
574     fib_table = fib_table_get(fib_index, prefix->fp_proto);
575     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
576
577     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
578     {
579         /*
580          * removing an etry that does not exist. i'll allow it.
581          */
582     }
583     else
584     {
585         fib_entry_src_flag_t src_flag;
586         int was_sourced;
587
588         /*
589          * don't nobody go nowhere
590          */
591         fib_entry_lock(fib_entry_index);
592         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
593
594         src_flag = fib_entry_path_remove(fib_entry_index, source, rpath);
595
596         if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
597         {
598             /*
599              * last source gone. remove from the table
600              */
601             fib_table_entry_remove(fib_table, prefix, fib_entry_index);
602
603             /*
604              * now the entry is no longer in the table, we can
605              * inform the entries that it covers to re-calculate their cover
606              */
607             fib_entry_cover_change_notify(fib_entry_index,
608                                           FIB_NODE_INDEX_INVALID);
609         }
610         /*
611          * else
612          *   still has sources, leave it be.
613          */
614         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
615         {
616             fib_table->ft_src_route_counts[source]--;
617         }
618
619         fib_entry_unlock(fib_entry_index);
620     }
621 }
622
623 void
624 fib_table_entry_path_remove (u32 fib_index,
625                              const fib_prefix_t *prefix,
626                              fib_source_t source,
627                              fib_protocol_t next_hop_proto,
628                              const ip46_address_t *next_hop,
629                              u32 next_hop_sw_if_index,
630                              u32 next_hop_fib_index,
631                              u32 next_hop_weight,
632                              fib_route_path_flags_t path_flags)
633 {
634     /*
635      * 1 is it present
636      *   yes => remove source
637      *    2 - is it still sourced?
638      *      no => cover walk
639      */
640     fib_route_path_t path = {
641         .frp_proto = next_hop_proto,
642         .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
643         .frp_sw_if_index = next_hop_sw_if_index,
644         .frp_fib_index = next_hop_fib_index,
645         .frp_weight = next_hop_weight,
646         .frp_flags = path_flags,
647     };
648     fib_route_path_t *paths = NULL;
649
650     fib_table_route_path_fixup(prefix, &path);
651     vec_add1(paths, path);
652
653     fib_table_entry_path_remove2(fib_index, prefix, source, paths);
654
655     vec_free(paths);
656 }
657
658 static int
659 fib_route_path_cmp_for_sort (void * v1,
660                              void * v2)
661 {
662     return (fib_route_path_cmp(v1, v2));
663 }
664
665 fib_node_index_t
666 fib_table_entry_update (u32 fib_index,
667                         const fib_prefix_t *prefix,
668                         fib_source_t source,
669                         fib_entry_flag_t flags,
670                         const fib_route_path_t *paths)
671 {
672     fib_node_index_t fib_entry_index;
673     fib_table_t *fib_table;
674
675     fib_table = fib_table_get(fib_index, prefix->fp_proto);
676     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
677
678     /*
679      * sort the paths provided by the control plane. this means
680      * the paths and the extension on the entry will be sorted.
681      */
682     vec_sort_with_function(((fib_route_path_t*)paths), // const cast
683                            fib_route_path_cmp_for_sort);
684
685     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
686     {
687         fib_entry_index = fib_entry_create(fib_index, prefix,
688                                            source, flags,
689                                            paths);
690
691         fib_table_entry_insert(fib_table, prefix, fib_entry_index);
692         fib_table->ft_src_route_counts[source]++;
693     }
694     else
695     {
696         int was_sourced;
697
698         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
699         fib_entry_update(fib_entry_index, source, flags, paths);
700
701         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
702         {
703             fib_table->ft_src_route_counts[source]++;
704         }
705     }
706
707     return (fib_entry_index);
708 }
709
710 fib_node_index_t
711 fib_table_entry_update_one_path (u32 fib_index,
712                                  const fib_prefix_t *prefix,
713                                  fib_source_t source,
714                                  fib_entry_flag_t flags,
715                                  fib_protocol_t next_hop_proto,
716                                  const ip46_address_t *next_hop,
717                                  u32 next_hop_sw_if_index,
718                                  u32 next_hop_fib_index,
719                                  u32 next_hop_weight,
720                                  mpls_label_t next_hop_label,
721                                  fib_route_path_flags_t path_flags)
722 {
723     fib_node_index_t fib_entry_index;
724     fib_route_path_t path = {
725         .frp_proto = next_hop_proto,
726         .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
727         .frp_sw_if_index = next_hop_sw_if_index,
728         .frp_fib_index = next_hop_fib_index,
729         .frp_weight = next_hop_weight,
730         .frp_flags = path_flags,
731         .frp_label = next_hop_label,
732     };
733     fib_route_path_t *paths = NULL;
734
735     fib_table_route_path_fixup(prefix, &path);
736     vec_add1(paths, path);
737
738     fib_entry_index = 
739         fib_table_entry_update(fib_index, prefix, source, flags, paths);
740
741     vec_free(paths);
742
743     return (fib_entry_index);
744 }
745
746 static void
747 fib_table_entry_delete_i (u32 fib_index,
748                           fib_node_index_t fib_entry_index,
749                           const fib_prefix_t *prefix,
750                           fib_source_t source)
751 {
752     fib_entry_src_flag_t src_flag;
753     fib_table_t *fib_table;
754     int was_sourced;
755
756     fib_table = fib_table_get(fib_index, prefix->fp_proto);
757     was_sourced = fib_entry_is_sourced(fib_entry_index, source);
758
759     /*
760      * don't nobody go nowhere
761      */
762     fib_entry_lock(fib_entry_index);
763
764     src_flag = fib_entry_delete(fib_entry_index, source);
765
766     if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
767     {
768         /*
769          * last source gone. remove from the table
770          */
771         fib_table_entry_remove(fib_table, prefix, fib_entry_index);
772
773         /*
774          * now the entry is no longer in the table, we can
775          * inform the entries that it covers to re-calculate their cover
776          */
777         fib_entry_cover_change_notify(fib_entry_index,
778                                       FIB_NODE_INDEX_INVALID);
779     }
780     /*
781      * else
782      *   still has sources, leave it be.
783      */
784     if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
785     {
786         fib_table->ft_src_route_counts[source]--;
787     }
788
789     fib_entry_unlock(fib_entry_index);
790 }
791
792 void
793 fib_table_entry_delete (u32 fib_index,
794                         const fib_prefix_t *prefix,
795                         fib_source_t source)
796 {
797     fib_node_index_t fib_entry_index;
798
799     fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
800
801     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
802     {
803         /*
804          * removing an etry that does not exist.
805          * i'll allow it, but i won't like it.
806          */
807         clib_warning("%U not in FIB", format_fib_prefix, prefix);
808     }
809     else
810     {
811         fib_table_entry_delete_i(fib_index, fib_entry_index, prefix, source);
812     }
813 }
814
815 void
816 fib_table_entry_delete_index (fib_node_index_t fib_entry_index,
817                               fib_source_t source)
818 {
819     fib_prefix_t prefix;
820
821     fib_entry_get_prefix(fib_entry_index, &prefix);
822
823     fib_table_entry_delete_i(fib_entry_get_fib_index(fib_entry_index),
824                              fib_entry_index, &prefix, source);
825 }
826
827 fib_node_index_t
828 fib_table_entry_local_label_add (u32 fib_index,
829                                  const fib_prefix_t *prefix,
830                                  mpls_label_t label)
831 {
832     fib_node_index_t fib_entry_index;
833  
834     fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
835
836     if (FIB_NODE_INDEX_INVALID == fib_entry_index ||
837         !fib_entry_is_sourced(fib_entry_index, FIB_SOURCE_MPLS))
838     {
839         /*
840          * only source the prefix once. this allows the label change
841          * operation to work
842          */
843         fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix,
844                                                           FIB_SOURCE_MPLS,
845                                                           FIB_ENTRY_FLAG_NONE,
846                                                           NULL);
847     }
848
849     fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &label);
850
851     return (fib_entry_index);
852 }
853
854 void
855 fib_table_entry_local_label_remove (u32 fib_index,
856                                     const fib_prefix_t *prefix,
857                                     mpls_label_t label)
858 {
859     fib_node_index_t fib_entry_index;
860     const void *data;
861     mpls_label_t pl;
862
863     fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
864
865     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
866         return;
867
868     data = fib_entry_get_source_data(fib_entry_index, FIB_SOURCE_MPLS);
869
870     if (NULL == data)
871         return;
872
873     pl = *(mpls_label_t*)data;
874
875     if (pl != label)
876         return;
877
878     pl = MPLS_LABEL_INVALID;
879
880     fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &pl);
881     fib_table_entry_special_remove(fib_index,
882                                    prefix,
883                                    FIB_SOURCE_MPLS);
884 }
885
886 u32
887 fib_table_get_index_for_sw_if_index (fib_protocol_t proto,
888                                      u32 sw_if_index)
889 {
890     switch (proto)
891     {
892     case FIB_PROTOCOL_IP4:
893         return (ip4_fib_table_get_index_for_sw_if_index(sw_if_index));
894     case FIB_PROTOCOL_IP6:
895         return (ip6_fib_table_get_index_for_sw_if_index(sw_if_index));
896     case FIB_PROTOCOL_MPLS:
897         return (mpls_fib_table_get_index_for_sw_if_index(sw_if_index));
898     }
899     return (~0);
900 }
901
902 flow_hash_config_t
903 fib_table_get_flow_hash_config (u32 fib_index,
904                                 fib_protocol_t proto)
905 {
906     switch (proto)
907     {
908     case FIB_PROTOCOL_IP4:
909         return (ip4_fib_table_get_flow_hash_config(fib_index));
910     case FIB_PROTOCOL_IP6:
911         return (ip6_fib_table_get_flow_hash_config(fib_index));
912     case FIB_PROTOCOL_MPLS:
913         return (mpls_fib_table_get_flow_hash_config(fib_index));
914     }
915     return (0);
916 }
917
918
919 u32
920 fib_table_get_table_id_for_sw_if_index (fib_protocol_t proto,
921                                         u32 sw_if_index)
922 {
923     fib_table_t *fib_table;
924
925     fib_table = fib_table_get(fib_table_get_index_for_sw_if_index(
926                                   proto, sw_if_index),
927                               proto);
928
929     return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
930 }
931
932 u32
933 fib_table_find (fib_protocol_t proto,
934                 u32 table_id)
935 {
936     switch (proto)
937     {
938     case FIB_PROTOCOL_IP4:
939         return (ip4_fib_index_from_table_id(table_id));
940     case FIB_PROTOCOL_IP6:
941         return (ip6_fib_index_from_table_id(table_id));
942     case FIB_PROTOCOL_MPLS:
943         return (mpls_fib_index_from_table_id(table_id));
944     }
945     return (~0);
946 }
947
948 u32
949 fib_table_find_or_create_and_lock (fib_protocol_t proto,
950                                    u32 table_id)
951 {
952     fib_table_t *fib_table;
953     fib_node_index_t fi;
954
955     switch (proto)
956     {
957     case FIB_PROTOCOL_IP4:
958         fi = ip4_fib_table_find_or_create_and_lock(table_id);
959         break;
960     case FIB_PROTOCOL_IP6:
961         fi = ip6_fib_table_find_or_create_and_lock(table_id);
962         break;
963     case FIB_PROTOCOL_MPLS:
964         fi = mpls_fib_table_find_or_create_and_lock(table_id);
965         break;
966     default:
967         return (~0);        
968     }
969
970     fib_table = fib_table_get(fi, proto);
971
972     fib_table->ft_desc = format(NULL, "%U-VRF:%d",
973                                 format_fib_protocol, proto,
974                                 table_id);
975
976     return (fi);
977 }
978
979 u32
980 fib_table_create_and_lock (fib_protocol_t proto,
981                            const char *const fmt,
982                            ...)
983 {
984     fib_table_t *fib_table;
985     fib_node_index_t fi;
986     va_list ap;
987
988     va_start(ap, fmt);
989
990     switch (proto)
991     {
992     case FIB_PROTOCOL_IP4:
993         fi = ip4_fib_table_create_and_lock();
994         break;
995     case FIB_PROTOCOL_IP6:
996         fi = ip6_fib_table_create_and_lock();
997         break;
998      case FIB_PROTOCOL_MPLS:
999         fi = mpls_fib_table_create_and_lock();
1000         break;
1001    default:
1002         return (~0);        
1003     }
1004
1005     fib_table = fib_table_get(fi, proto);
1006
1007     fib_table->ft_desc = va_format(fib_table->ft_desc, fmt, &ap);
1008
1009     va_end(ap);
1010     return (fi);
1011 }
1012
1013 static void
1014 fib_table_destroy (fib_table_t *fib_table)
1015 {
1016     vec_free(fib_table->ft_desc);
1017
1018     switch (fib_table->ft_proto)
1019     {
1020     case FIB_PROTOCOL_IP4:
1021         ip4_fib_table_destroy(&fib_table->v4);
1022         break;
1023     case FIB_PROTOCOL_IP6:
1024         ip6_fib_table_destroy(fib_table->ft_index);
1025         break;
1026     case FIB_PROTOCOL_MPLS:
1027         mpls_fib_table_destroy(&fib_table->mpls);
1028         break;
1029     }
1030 }
1031
1032 void
1033 fib_table_unlock (u32 fib_index,
1034                   fib_protocol_t proto)
1035 {
1036     fib_table_t *fib_table;
1037
1038     fib_table = fib_table_get(fib_index, proto);
1039     fib_table->ft_locks--;
1040
1041     if (0 == fib_table->ft_locks)
1042     {
1043         fib_table_destroy(fib_table);
1044     }
1045 }
1046 void
1047 fib_table_lock (u32 fib_index,
1048                 fib_protocol_t proto)
1049 {
1050     fib_table_t *fib_table;
1051
1052     fib_table = fib_table_get(fib_index, proto);
1053     fib_table->ft_locks++;
1054 }
1055
1056 u32
1057 fib_table_get_num_entries (u32 fib_index,
1058                            fib_protocol_t proto,
1059                            fib_source_t source)
1060 {
1061     fib_table_t *fib_table;
1062
1063     fib_table = fib_table_get(fib_index, proto);
1064
1065     return (fib_table->ft_src_route_counts[source]);
1066 }
1067
1068 u8*
1069 format_fib_table_name (u8* s, va_list ap)
1070 {
1071     fib_node_index_t fib_index = va_arg(ap, fib_node_index_t);
1072     fib_protocol_t proto = va_arg(ap, int); // int promotion
1073     fib_table_t *fib_table;
1074
1075     fib_table = fib_table_get(fib_index, proto);
1076
1077     s = format(s, "%v", fib_table->ft_desc);
1078
1079     return (s);
1080 }
1081
1082 void
1083 fib_table_flush (u32 fib_index,
1084                  fib_protocol_t proto,
1085                  fib_source_t source)
1086 {
1087     // FIXME
1088     ASSERT(0);
1089 }