fib: Table Replace
[vpp.git] / src / 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 const static char * fib_table_flags_strings[] = FIB_TABLE_ATTRIBUTES;
27
28 fib_table_t *
29 fib_table_get (fib_node_index_t index,
30                fib_protocol_t proto)
31 {
32     switch (proto)
33     {
34     case FIB_PROTOCOL_IP4:
35         return (pool_elt_at_index(ip4_main.fibs, index));
36     case FIB_PROTOCOL_IP6:
37         return (pool_elt_at_index(ip6_main.fibs, index));
38     case FIB_PROTOCOL_MPLS:
39         return (pool_elt_at_index(mpls_main.fibs, index));
40     }
41     ASSERT(0);
42     return (NULL);
43 }
44
45 static inline fib_node_index_t
46 fib_table_lookup_i (fib_table_t *fib_table,
47                     const fib_prefix_t *prefix)
48 {
49     switch (prefix->fp_proto)
50     {
51     case FIB_PROTOCOL_IP4:
52         return (ip4_fib_table_lookup(ip4_fib_get(fib_table->ft_index),
53                                      &prefix->fp_addr.ip4,
54                                      prefix->fp_len));
55     case FIB_PROTOCOL_IP6:
56         return (ip6_fib_table_lookup(fib_table->ft_index,
57                                      &prefix->fp_addr.ip6,
58                                      prefix->fp_len));
59     case FIB_PROTOCOL_MPLS:
60         return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
61                                       prefix->fp_label,
62                                       prefix->fp_eos));
63     }
64     return (FIB_NODE_INDEX_INVALID);
65 }
66
67 fib_node_index_t
68 fib_table_lookup (u32 fib_index,
69                   const fib_prefix_t *prefix)
70 {
71     return (fib_table_lookup_i(fib_table_get(fib_index, prefix->fp_proto), prefix));
72 }
73
74 static inline fib_node_index_t
75 fib_table_lookup_exact_match_i (const fib_table_t *fib_table,
76                                 const fib_prefix_t *prefix)
77 {
78     switch (prefix->fp_proto)
79     {
80     case FIB_PROTOCOL_IP4:
81         return (ip4_fib_table_lookup_exact_match(ip4_fib_get(fib_table->ft_index),
82                                                  &prefix->fp_addr.ip4,
83                                                  prefix->fp_len));
84     case FIB_PROTOCOL_IP6:
85         return (ip6_fib_table_lookup_exact_match(fib_table->ft_index,
86                                                  &prefix->fp_addr.ip6,
87                                                  prefix->fp_len));
88     case FIB_PROTOCOL_MPLS:
89         return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
90                                       prefix->fp_label,
91                                       prefix->fp_eos));
92     }
93     return (FIB_NODE_INDEX_INVALID);
94 }
95
96 fib_node_index_t
97 fib_table_lookup_exact_match (u32 fib_index,
98                               const fib_prefix_t *prefix)
99 {
100     return (fib_table_lookup_exact_match_i(fib_table_get(fib_index,
101                                                          prefix->fp_proto),
102                                            prefix));
103 }
104
105 static fib_node_index_t
106 fib_table_get_less_specific_i (fib_table_t *fib_table,
107                                const fib_prefix_t *prefix)
108 {
109     fib_prefix_t pfx;
110
111     pfx = *prefix;
112
113     if (FIB_PROTOCOL_MPLS == pfx.fp_proto)
114     {
115         return (FIB_NODE_INDEX_INVALID);
116     }
117
118     /*
119      * in the absence of a tree structure for the table that allows for an O(1)
120      * parent get, a cheeky way to find the cover is to LPM for the prefix with
121      * mask-1.
122      * there should always be a cover, though it may be the default route. the
123      * default route's cover is the default route.
124      */
125     if (pfx.fp_len != 0) {
126         pfx.fp_len -= 1;
127     }
128
129     return (fib_table_lookup_i(fib_table, &pfx));    
130 }
131
132 fib_node_index_t
133 fib_table_get_less_specific (u32 fib_index,
134                              const fib_prefix_t *prefix)
135 {
136     return (fib_table_get_less_specific_i(fib_table_get(fib_index,
137                                                         prefix->fp_proto),
138                                           prefix));
139 }
140
141 static void
142 fib_table_entry_remove (fib_table_t *fib_table,
143                         const fib_prefix_t *prefix,
144                         fib_node_index_t fib_entry_index)
145 {
146     vlib_smp_unsafe_warning();
147
148     fib_table->ft_total_route_counts--;
149
150     switch (prefix->fp_proto)
151     {
152     case FIB_PROTOCOL_IP4:
153         ip4_fib_table_entry_remove(ip4_fib_get(fib_table->ft_index),
154                                    &prefix->fp_addr.ip4,
155                                    prefix->fp_len);
156         break;
157     case FIB_PROTOCOL_IP6:
158         ip6_fib_table_entry_remove(fib_table->ft_index,
159                                    &prefix->fp_addr.ip6,
160                                    prefix->fp_len);
161         break;
162     case FIB_PROTOCOL_MPLS:
163         mpls_fib_table_entry_remove(mpls_fib_get(fib_table->ft_index),
164                                     prefix->fp_label,
165                                     prefix->fp_eos);
166         break;
167     }
168
169     fib_entry_unlock(fib_entry_index);
170 }
171
172 static void
173 fib_table_post_insert_actions (fib_table_t *fib_table,
174                                const fib_prefix_t *prefix,
175                                fib_node_index_t fib_entry_index)
176 {
177     fib_node_index_t fib_entry_cover_index;
178
179     /*
180      * no cover relationships in the MPLS FIB
181      */
182     if (FIB_PROTOCOL_MPLS == prefix->fp_proto)
183         return;
184
185     /*
186      * find  the covering entry
187      */
188     fib_entry_cover_index = fib_table_get_less_specific_i(fib_table, prefix);
189     /*
190      * the indicies are the same when the default route is first added
191      */
192     if (fib_entry_cover_index != fib_entry_index)
193     {
194         /*
195          * push any inherting sources from the cover onto the covered
196          */
197         fib_entry_inherit(fib_entry_cover_index,
198                           fib_entry_index);
199
200         /*
201          * inform the covering entry that a new more specific
202          * has been inserted beneath it.
203          * If the prefix that has been inserted is a host route
204          * then it is not possible that it will be the cover for any
205          * other entry, so we can elide the walk. This is particularly
206          * beneficial since there are often many host entries sharing the
207          * same cover (i.e. ADJ or RR sourced entries).
208          */
209         if (!fib_entry_is_host(fib_entry_index))
210         {
211             fib_entry_cover_change_notify(fib_entry_cover_index,
212                                           fib_entry_index);
213         }
214     }
215 }
216
217 static void
218 fib_table_entry_insert (fib_table_t *fib_table,
219                         const fib_prefix_t *prefix,
220                         fib_node_index_t fib_entry_index)
221 {
222     vlib_smp_unsafe_warning();
223
224     fib_entry_lock(fib_entry_index);
225     fib_table->ft_total_route_counts++;
226
227     switch (prefix->fp_proto)
228     {
229     case FIB_PROTOCOL_IP4:
230         ip4_fib_table_entry_insert(ip4_fib_get(fib_table->ft_index),
231                                    &prefix->fp_addr.ip4,
232                                    prefix->fp_len,
233                                    fib_entry_index);
234         break;
235     case FIB_PROTOCOL_IP6:
236         ip6_fib_table_entry_insert(fib_table->ft_index,
237                                    &prefix->fp_addr.ip6,
238                                    prefix->fp_len,
239                                    fib_entry_index);
240         break;
241     case FIB_PROTOCOL_MPLS:
242         mpls_fib_table_entry_insert(mpls_fib_get(fib_table->ft_index),
243                                     prefix->fp_label,
244                                     prefix->fp_eos,
245                                     fib_entry_index);
246         break;
247     }
248
249     fib_table_post_insert_actions(fib_table, prefix, fib_entry_index);
250 }
251
252 void
253 fib_table_fwding_dpo_update (u32 fib_index,
254                              const fib_prefix_t *prefix,
255                              const dpo_id_t *dpo)
256 {
257     vlib_smp_unsafe_warning();
258
259     switch (prefix->fp_proto)
260     {
261     case FIB_PROTOCOL_IP4:
262         return (ip4_fib_table_fwding_dpo_update(ip4_fib_get(fib_index),
263                                                 &prefix->fp_addr.ip4,
264                                                 prefix->fp_len,
265                                                 dpo));
266     case FIB_PROTOCOL_IP6:
267         return (ip6_fib_table_fwding_dpo_update(fib_index,
268                                                 &prefix->fp_addr.ip6,
269                                                 prefix->fp_len,
270                                                 dpo));
271     case FIB_PROTOCOL_MPLS:
272         return (mpls_fib_forwarding_table_update(mpls_fib_get(fib_index),
273                                                  prefix->fp_label,
274                                                  prefix->fp_eos,
275                                                  dpo));
276     }
277 }
278
279 void
280 fib_table_fwding_dpo_remove (u32 fib_index,
281                              const fib_prefix_t *prefix,
282                              const dpo_id_t *dpo)
283 {
284     vlib_smp_unsafe_warning();
285
286     switch (prefix->fp_proto)
287     {
288     case FIB_PROTOCOL_IP4:
289         return (ip4_fib_table_fwding_dpo_remove(ip4_fib_get(fib_index),
290                                                 &prefix->fp_addr.ip4,
291                                                 prefix->fp_len,
292                                                 dpo,
293                                                 fib_table_get_less_specific(fib_index,
294                                                                             prefix)));
295     case FIB_PROTOCOL_IP6:
296         return (ip6_fib_table_fwding_dpo_remove(fib_index,
297                                                 &prefix->fp_addr.ip6,
298                                                 prefix->fp_len,
299                                                 dpo));
300     case FIB_PROTOCOL_MPLS:
301         return (mpls_fib_forwarding_table_reset(mpls_fib_get(fib_index),
302                                                 prefix->fp_label,
303                                                 prefix->fp_eos));
304     }
305 }
306
307
308 fib_node_index_t
309 fib_table_entry_special_dpo_add (u32 fib_index,
310                                  const fib_prefix_t *prefix,
311                                  fib_source_t source,
312                                  fib_entry_flag_t flags,
313                                  const dpo_id_t *dpo)
314 {
315     fib_node_index_t fib_entry_index;
316     fib_table_t *fib_table;
317
318     fib_table = fib_table_get(fib_index, prefix->fp_proto);
319     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
320
321     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
322     {
323         fib_entry_index = fib_entry_create_special(fib_index, prefix,
324                                                    source, flags,
325                                                    dpo);
326
327         fib_table_entry_insert(fib_table, prefix, fib_entry_index);
328         fib_table->ft_src_route_counts[source]++;
329     }
330     else
331     {
332         int was_sourced;
333
334         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
335         fib_entry_special_add(fib_entry_index, source, flags, dpo);
336
337         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
338         {
339             fib_table->ft_src_route_counts[source]++;
340         }
341     }
342
343
344     return (fib_entry_index);
345 }
346
347 fib_node_index_t
348 fib_table_entry_special_dpo_update (u32 fib_index,
349                                     const fib_prefix_t *prefix,
350                                     fib_source_t source,
351                                     fib_entry_flag_t flags,
352                                     const dpo_id_t *dpo)
353 {
354     fib_node_index_t fib_entry_index;
355     fib_table_t *fib_table;
356
357     fib_table = fib_table_get(fib_index, prefix->fp_proto);
358     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
359
360     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
361     {
362         fib_entry_index = fib_entry_create_special(fib_index, prefix,
363                                                    source, flags,
364                                                    dpo);
365
366         fib_table_entry_insert(fib_table, prefix, fib_entry_index);
367         fib_table->ft_src_route_counts[source]++;
368     }
369     else
370     {
371         int was_sourced;
372
373         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
374
375         if (was_sourced)
376             fib_entry_special_update(fib_entry_index, source, flags, dpo);
377         else
378             fib_entry_special_add(fib_entry_index, source, flags, dpo);
379
380         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
381         {
382             fib_table->ft_src_route_counts[source]++;
383         }
384     }
385
386     return (fib_entry_index);
387 }
388
389 fib_node_index_t
390 fib_table_entry_special_add (u32 fib_index,
391                              const fib_prefix_t *prefix,
392                              fib_source_t source,
393                              fib_entry_flag_t flags)
394 {
395     fib_node_index_t fib_entry_index;
396     dpo_id_t tmp_dpo = DPO_INVALID;
397
398     dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto)));
399  
400     fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, source,
401                                                       flags, &tmp_dpo);
402
403     dpo_unlock(&tmp_dpo);
404
405     return (fib_entry_index);
406 }
407
408 void
409 fib_table_entry_special_remove (u32 fib_index,
410                                 const fib_prefix_t *prefix,
411                                 fib_source_t source)
412 {
413     /*
414      * 1 is it present
415      *   yes => remove source
416      *    2 - is it still sourced?
417      *      no => cover walk
418      */
419     fib_node_index_t fib_entry_index;
420     fib_table_t *fib_table;
421
422     fib_table = fib_table_get(fib_index, prefix->fp_proto);
423     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
424
425     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
426     {
427         /*
428          * removing an etry that does not exist. i'll allow it.
429          */
430     }
431     else
432     {
433         fib_entry_src_flag_t src_flag;
434         int was_sourced;
435
436         /*
437          * don't nobody go nowhere
438          */
439         fib_entry_lock(fib_entry_index);
440         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
441
442         src_flag = fib_entry_special_remove(fib_entry_index, source);
443
444         if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
445         {
446             /*
447              * last source gone. remove from the table
448              */
449             fib_table_entry_remove(fib_table, prefix, fib_entry_index);
450
451             /*
452              * now the entry is no longer in the table, we can
453              * inform the entries that it covers to re-calculate their cover
454              */
455             fib_entry_cover_change_notify(fib_entry_index,
456                                           FIB_NODE_INDEX_INVALID);
457         }
458         /*
459          * else
460          *   still has sources, leave it be.
461          */
462         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
463         {
464             fib_table->ft_src_route_counts[source]--;
465         }
466
467         fib_entry_unlock(fib_entry_index);
468     }
469 }
470
471 /**
472  * fib_table_route_path_fixup
473  *
474  * Convert attached hosts to attached next-hops.
475  * 
476  * This special case is required because an attached path will link to a
477  * glean, and the FIB entry will have the interface or API/CLI source. When
478  * the ARP/ND process is completes then that source (which will provide a
479  * complete adjacency) will be lower priority and so the FIB entry will
480  * remain linked to a glean and traffic will never reach the hosts. For
481  * an ATTAHCED_HOST path we can link the path directly to the [incomplete]
482  * adjacency.
483  */
484 static void
485 fib_table_route_path_fixup (const fib_prefix_t *prefix,
486                             fib_entry_flag_t *eflags,
487                             fib_route_path_t *path)
488 {
489     /*
490      * not all zeros next hop &&
491      * is recursive path &&
492      * nexthop is same as the route's address
493      */
494     if ((!ip46_address_is_zero(&path->frp_addr)) &&
495         (~0 == path->frp_sw_if_index) &&
496         (0 == ip46_address_cmp(&path->frp_addr, &prefix->fp_addr)))
497     {
498         /* Prefix recurses via itse;f */
499         path->frp_flags |= FIB_ROUTE_PATH_DROP;
500     }
501     if (!(path->frp_flags & FIB_ROUTE_PATH_LOCAL) &&
502         fib_prefix_is_host(prefix) &&
503         ip46_address_is_zero(&path->frp_addr) &&
504         path->frp_sw_if_index != ~0 &&
505         path->frp_proto != DPO_PROTO_ETHERNET)
506     {
507         path->frp_addr = prefix->fp_addr;
508         path->frp_flags |= FIB_ROUTE_PATH_ATTACHED;
509     }
510     if (*eflags & FIB_ENTRY_FLAG_DROP)
511     {
512         path->frp_flags |= FIB_ROUTE_PATH_DROP;
513     }
514     if (*eflags & FIB_ENTRY_FLAG_LOCAL)
515     {
516         path->frp_flags |= FIB_ROUTE_PATH_LOCAL;
517     }
518     if (*eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
519     {
520         path->frp_flags |= FIB_ROUTE_PATH_EXCLUSIVE;
521     }
522     if (path->frp_flags & FIB_ROUTE_PATH_LOCAL)
523     {
524         *eflags |= FIB_ENTRY_FLAG_LOCAL;
525
526         if (path->frp_sw_if_index != ~0)
527         {
528             *eflags |= FIB_ENTRY_FLAG_CONNECTED;
529         }
530     }
531 }
532
533 fib_node_index_t
534 fib_table_entry_path_add (u32 fib_index,
535                           const fib_prefix_t *prefix,
536                           fib_source_t source,
537                           fib_entry_flag_t flags,
538                           dpo_proto_t next_hop_proto,
539                           const ip46_address_t *next_hop,
540                           u32 next_hop_sw_if_index,
541                           u32 next_hop_fib_index,
542                           u32 next_hop_weight,
543                           fib_mpls_label_t *next_hop_labels,
544                           fib_route_path_flags_t path_flags)
545 {
546     fib_route_path_t path = {
547         .frp_proto = next_hop_proto,
548         .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
549         .frp_sw_if_index = next_hop_sw_if_index,
550         .frp_fib_index = next_hop_fib_index,
551         .frp_weight = next_hop_weight,
552         .frp_flags = path_flags,
553         .frp_rpf_id = INDEX_INVALID,
554         .frp_label_stack = next_hop_labels,
555     };
556     fib_node_index_t fib_entry_index;
557     fib_route_path_t *paths = NULL;
558
559     vec_add1(paths, path);
560
561     fib_entry_index = fib_table_entry_path_add2(fib_index, prefix,
562                                                 source, flags, paths);
563
564     vec_free(paths);
565     return (fib_entry_index);
566 }
567
568 fib_node_index_t
569 fib_table_entry_path_add2 (u32 fib_index,
570                            const fib_prefix_t *prefix,
571                            fib_source_t source,
572                            fib_entry_flag_t flags,
573                            fib_route_path_t *rpaths)
574 {
575     fib_node_index_t fib_entry_index;
576     fib_table_t *fib_table;
577     u32 ii;
578
579     fib_table = fib_table_get(fib_index, prefix->fp_proto);
580     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
581
582     for (ii = 0; ii < vec_len(rpaths); ii++)
583     {
584         fib_table_route_path_fixup(prefix, &flags, &rpaths[ii]);
585     }
586
587     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
588     {
589         fib_entry_index = fib_entry_create(fib_index, prefix,
590                                            source, flags,
591                                            rpaths);
592
593         fib_table_entry_insert(fib_table, prefix, fib_entry_index);
594         fib_table->ft_src_route_counts[source]++;
595     }
596     else
597     {
598         int was_sourced;
599
600         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
601         fib_entry_path_add(fib_entry_index, source, flags, rpaths);;
602
603         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
604         {
605             fib_table->ft_src_route_counts[source]++;
606         }
607     }
608
609     return (fib_entry_index);
610 }
611
612 void
613 fib_table_entry_path_remove2 (u32 fib_index,
614                               const fib_prefix_t *prefix,
615                               fib_source_t source,
616                               fib_route_path_t *rpaths)
617 {
618     /*
619      * 1 is it present
620      *   yes => remove source
621      *    2 - is it still sourced?
622      *      no => cover walk
623      */
624     fib_node_index_t fib_entry_index;
625     fib_route_path_t *rpath;
626     fib_table_t *fib_table;
627
628     fib_table = fib_table_get(fib_index, prefix->fp_proto);
629     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
630
631     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
632     {
633         /*
634          * removing an etry that does not exist. i'll allow it.
635          */
636     }
637     else
638     {
639         fib_entry_src_flag_t src_flag;
640         int was_sourced;
641
642         /*
643          * if it's not sourced, then there's nowt to remove
644          */
645         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
646         if (!was_sourced)
647         {
648             return;
649         }
650
651         /*
652          * don't nobody go nowhere
653          */
654         fib_entry_lock(fib_entry_index);
655
656         vec_foreach(rpath, rpaths)
657         {
658             fib_entry_flag_t eflags;
659
660             eflags = fib_entry_get_flags_for_source(fib_entry_index,
661                                                     source);
662             fib_table_route_path_fixup(prefix, &eflags, rpath);
663         }
664
665         src_flag = fib_entry_path_remove(fib_entry_index, source, rpaths);
666
667         if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
668         {
669             /*
670              * last source gone. remove from the table
671              */
672             fib_table_entry_remove(fib_table, prefix, fib_entry_index);
673
674             /*
675              * now the entry is no longer in the table, we can
676              * inform the entries that it covers to re-calculate their cover
677              */
678             fib_entry_cover_change_notify(fib_entry_index,
679                                           FIB_NODE_INDEX_INVALID);
680         }
681         /*
682          * else
683          *   still has sources, leave it be.
684          */
685         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
686         {
687             fib_table->ft_src_route_counts[source]--;
688         }
689
690         fib_entry_unlock(fib_entry_index);
691     }
692 }
693
694 void
695 fib_table_entry_path_remove (u32 fib_index,
696                              const fib_prefix_t *prefix,
697                              fib_source_t source,
698                              dpo_proto_t next_hop_proto,
699                              const ip46_address_t *next_hop,
700                              u32 next_hop_sw_if_index,
701                              u32 next_hop_fib_index,
702                              u32 next_hop_weight,
703                              fib_route_path_flags_t path_flags)
704 {
705     /*
706      * 1 is it present
707      *   yes => remove source
708      *    2 - is it still sourced?
709      *      no => cover walk
710      */
711     fib_route_path_t path = {
712         .frp_proto = next_hop_proto,
713         .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
714         .frp_sw_if_index = next_hop_sw_if_index,
715         .frp_fib_index = next_hop_fib_index,
716         .frp_weight = next_hop_weight,
717         .frp_flags = path_flags,
718     };
719     fib_route_path_t *paths = NULL;
720
721     vec_add1(paths, path);
722
723     fib_table_entry_path_remove2(fib_index, prefix, source, paths);
724
725     vec_free(paths);
726 }
727
728 static int
729 fib_route_path_cmp_for_sort (void * v1,
730                              void * v2)
731 {
732     return (fib_route_path_cmp(v1, v2));
733 }
734
735 fib_node_index_t
736 fib_table_entry_update (u32 fib_index,
737                         const fib_prefix_t *prefix,
738                         fib_source_t source,
739                         fib_entry_flag_t flags,
740                         fib_route_path_t *paths)
741 {
742     fib_node_index_t fib_entry_index;
743     fib_table_t *fib_table;
744     u32 ii;
745
746     fib_table = fib_table_get(fib_index, prefix->fp_proto);
747     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
748
749     for (ii = 0; ii < vec_len(paths); ii++)
750     {
751         fib_table_route_path_fixup(prefix, &flags, &paths[ii]);
752     }
753     /*
754      * sort the paths provided by the control plane. this means
755      * the paths and the extension on the entry will be sorted.
756      */
757     vec_sort_with_function(paths, fib_route_path_cmp_for_sort);
758
759     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
760     {
761         fib_entry_index = fib_entry_create(fib_index, prefix,
762                                            source, flags,
763                                            paths);
764
765         fib_table_entry_insert(fib_table, prefix, fib_entry_index);
766         fib_table->ft_src_route_counts[source]++;
767     }
768     else
769     {
770         int was_sourced;
771
772         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
773         fib_entry_update(fib_entry_index, source, flags, paths);
774
775         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
776         {
777             fib_table->ft_src_route_counts[source]++;
778         }
779     }
780
781     return (fib_entry_index);
782 }
783
784 fib_node_index_t
785 fib_table_entry_update_one_path (u32 fib_index,
786                                  const fib_prefix_t *prefix,
787                                  fib_source_t source,
788                                  fib_entry_flag_t flags,
789                                  dpo_proto_t next_hop_proto,
790                                  const ip46_address_t *next_hop,
791                                  u32 next_hop_sw_if_index,
792                                  u32 next_hop_fib_index,
793                                  u32 next_hop_weight,
794                                  fib_mpls_label_t *next_hop_labels,
795                                  fib_route_path_flags_t path_flags)
796 {
797     fib_node_index_t fib_entry_index;
798     fib_route_path_t path = {
799         .frp_proto = next_hop_proto,
800         .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
801         .frp_sw_if_index = next_hop_sw_if_index,
802         .frp_fib_index = next_hop_fib_index,
803         .frp_weight = next_hop_weight,
804         .frp_flags = path_flags,
805         .frp_label_stack = next_hop_labels,
806     };
807     fib_route_path_t *paths = NULL;
808
809     vec_add1(paths, path);
810
811     fib_entry_index = 
812         fib_table_entry_update(fib_index, prefix, source, flags, paths);
813
814     vec_free(paths);
815
816     return (fib_entry_index);
817 }
818
819 static void
820 fib_table_entry_delete_i (u32 fib_index,
821                           fib_node_index_t fib_entry_index,
822                           const fib_prefix_t *prefix,
823                           fib_source_t source)
824 {
825     fib_entry_src_flag_t src_flag;
826     fib_table_t *fib_table;
827     int was_sourced;
828
829     fib_table = fib_table_get(fib_index, prefix->fp_proto);
830     was_sourced = fib_entry_is_sourced(fib_entry_index, source);
831
832     /*
833      * don't nobody go nowhere
834      */
835     fib_entry_lock(fib_entry_index);
836
837     src_flag = fib_entry_delete(fib_entry_index, source);
838
839     if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
840     {
841         /*
842          * last source gone. remove from the table
843          */
844         fib_table_entry_remove(fib_table, prefix, fib_entry_index);
845
846         /*
847          * now the entry is no longer in the table, we can
848          * inform the entries that it covers to re-calculate their cover
849          */
850         fib_entry_cover_change_notify(fib_entry_index,
851                                       FIB_NODE_INDEX_INVALID);
852     }
853     /*
854      * else
855      *   still has sources, leave it be.
856      */
857     if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
858     {
859         fib_table->ft_src_route_counts[source]--;
860     }
861
862     fib_entry_unlock(fib_entry_index);
863 }
864
865 void
866 fib_table_entry_delete (u32 fib_index,
867                         const fib_prefix_t *prefix,
868                         fib_source_t source)
869 {
870     fib_node_index_t fib_entry_index;
871
872     fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
873
874     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
875     {
876         /*
877          * removing an etry that does not exist.
878          * i'll allow it, but i won't like it.
879          */
880         if (0)
881             clib_warning("%U not in FIB", format_fib_prefix, prefix);
882     }
883     else
884     {
885         fib_table_entry_delete_i(fib_index, fib_entry_index, prefix, source);
886     }
887 }
888
889 void
890 fib_table_entry_delete_index (fib_node_index_t fib_entry_index,
891                               fib_source_t source)
892 {
893     const fib_prefix_t *prefix;
894
895     prefix = fib_entry_get_prefix(fib_entry_index);
896
897     fib_table_entry_delete_i(fib_entry_get_fib_index(fib_entry_index),
898                              fib_entry_index, prefix, source);
899 }
900
901 u32
902 fib_table_entry_get_stats_index (u32 fib_index,
903                                  const fib_prefix_t *prefix)
904 {
905     return (fib_entry_get_stats_index(
906                 fib_table_lookup_exact_match(fib_index, prefix)));
907 }
908
909 fib_node_index_t
910 fib_table_entry_local_label_add (u32 fib_index,
911                                  const fib_prefix_t *prefix,
912                                  mpls_label_t label)
913 {
914     fib_node_index_t fib_entry_index;
915  
916     fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
917
918     if (FIB_NODE_INDEX_INVALID == fib_entry_index ||
919         !fib_entry_is_sourced(fib_entry_index, FIB_SOURCE_MPLS))
920     {
921         /*
922          * only source the prefix once. this allows the label change
923          * operation to work
924          */
925         fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix,
926                                                           FIB_SOURCE_MPLS,
927                                                           FIB_ENTRY_FLAG_NONE,
928                                                           NULL);
929     }
930
931     fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &label);
932
933     return (fib_entry_index);
934 }
935
936 void
937 fib_table_entry_local_label_remove (u32 fib_index,
938                                     const fib_prefix_t *prefix,
939                                     mpls_label_t label)
940 {
941     fib_node_index_t fib_entry_index;
942     const void *data;
943     mpls_label_t pl;
944
945     fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
946
947     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
948         return;
949
950     data = fib_entry_get_source_data(fib_entry_index, FIB_SOURCE_MPLS);
951
952     if (NULL == data)
953         return;
954
955     pl = *(mpls_label_t*)data;
956
957     if (pl != label)
958         return;
959
960     pl = MPLS_LABEL_INVALID;
961
962     fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &pl);
963     fib_table_entry_special_remove(fib_index,
964                                    prefix,
965                                    FIB_SOURCE_MPLS);
966 }
967
968 u32
969 fib_table_get_index_for_sw_if_index (fib_protocol_t proto,
970                                      u32 sw_if_index)
971 {
972     switch (proto)
973     {
974     case FIB_PROTOCOL_IP4:
975         return (ip4_fib_table_get_index_for_sw_if_index(sw_if_index));
976     case FIB_PROTOCOL_IP6:
977         return (ip6_fib_table_get_index_for_sw_if_index(sw_if_index));
978     case FIB_PROTOCOL_MPLS:
979         return (mpls_fib_table_get_index_for_sw_if_index(sw_if_index));
980     }
981     return (~0);
982 }
983
984 flow_hash_config_t
985 fib_table_get_flow_hash_config (u32 fib_index,
986                                 fib_protocol_t proto)
987 {
988     fib_table_t *fib;
989
990     fib = fib_table_get(fib_index, proto);
991
992     return (fib->ft_flow_hash_config);
993 }
994
995 flow_hash_config_t
996 fib_table_get_default_flow_hash_config (fib_protocol_t proto)
997 {
998     switch (proto)
999     {
1000     case FIB_PROTOCOL_IP4:
1001     case FIB_PROTOCOL_IP6:
1002         return (IP_FLOW_HASH_DEFAULT);
1003
1004     case FIB_PROTOCOL_MPLS:
1005         return (MPLS_FLOW_HASH_DEFAULT);
1006     }
1007
1008     ASSERT(0);
1009     return (IP_FLOW_HASH_DEFAULT);
1010 }
1011
1012 /**
1013  * @brief Table set flow hash config context.
1014  */
1015 typedef struct fib_table_set_flow_hash_config_ctx_t_
1016 {
1017     /**
1018      * the flow hash config to set
1019      */
1020     flow_hash_config_t hash_config;
1021 } fib_table_set_flow_hash_config_ctx_t;
1022
1023 static fib_table_walk_rc_t
1024 fib_table_set_flow_hash_config_cb (fib_node_index_t fib_entry_index,
1025                                    void *arg)
1026 {
1027     fib_table_set_flow_hash_config_ctx_t *ctx = arg;
1028
1029     fib_entry_set_flow_hash_config(fib_entry_index, ctx->hash_config);
1030
1031     return (FIB_TABLE_WALK_CONTINUE);
1032 }
1033
1034 void
1035 fib_table_set_flow_hash_config (u32 fib_index,
1036                                 fib_protocol_t proto,
1037                                 flow_hash_config_t hash_config)
1038 {
1039     fib_table_set_flow_hash_config_ctx_t ctx = {
1040         .hash_config = hash_config,
1041     };
1042     fib_table_t *fib;
1043
1044     fib = fib_table_get(fib_index, proto);
1045     fib->ft_flow_hash_config = hash_config;
1046
1047     fib_table_walk(fib_index, proto,
1048                    fib_table_set_flow_hash_config_cb,
1049                    &ctx);
1050 }
1051
1052 u32
1053 fib_table_get_table_id_for_sw_if_index (fib_protocol_t proto,
1054                                         u32 sw_if_index)
1055 {
1056     fib_table_t *fib_table;
1057
1058     fib_table = fib_table_get(fib_table_get_index_for_sw_if_index(
1059                                   proto, sw_if_index),
1060                               proto);
1061
1062     return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1063 }
1064
1065 u32
1066 fib_table_get_table_id (u32 fib_index,
1067                         fib_protocol_t proto)
1068 {
1069     fib_table_t *fib_table;
1070
1071     fib_table = fib_table_get(fib_index, proto);
1072
1073     return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
1074 }
1075
1076 u32
1077 fib_table_find (fib_protocol_t proto,
1078                 u32 table_id)
1079 {
1080     switch (proto)
1081     {
1082     case FIB_PROTOCOL_IP4:
1083         return (ip4_fib_index_from_table_id(table_id));
1084     case FIB_PROTOCOL_IP6:
1085         return (ip6_fib_index_from_table_id(table_id));
1086     case FIB_PROTOCOL_MPLS:
1087         return (mpls_fib_index_from_table_id(table_id));
1088     }
1089     return (~0);
1090 }
1091
1092 static u32
1093 fib_table_find_or_create_and_lock_i (fib_protocol_t proto,
1094                                      u32 table_id,
1095                                      fib_source_t src,
1096                                      const u8 *name)
1097 {
1098     fib_table_t *fib_table;
1099     fib_node_index_t fi;
1100
1101     switch (proto)
1102     {
1103     case FIB_PROTOCOL_IP4:
1104         fi = ip4_fib_table_find_or_create_and_lock(table_id, src);
1105         break;
1106     case FIB_PROTOCOL_IP6:
1107         fi = ip6_fib_table_find_or_create_and_lock(table_id, src);
1108         break;
1109     case FIB_PROTOCOL_MPLS:
1110         fi = mpls_fib_table_find_or_create_and_lock(table_id, src);
1111         break;
1112     default:
1113         return (~0);        
1114     }
1115
1116     fib_table = fib_table_get(fi, proto);
1117
1118     if (NULL == fib_table->ft_desc)
1119     {
1120         if (name && name[0])
1121         {
1122             fib_table->ft_desc = format(NULL, "%s", name);
1123         }
1124         else
1125         {
1126             fib_table->ft_desc = format(NULL, "%U-VRF:%d",
1127                                         format_fib_protocol, proto,
1128                                         table_id);
1129         }
1130     }
1131
1132     return (fi);
1133 }
1134
1135 u32
1136 fib_table_find_or_create_and_lock (fib_protocol_t proto,
1137                                    u32 table_id,
1138                                    fib_source_t src)
1139 {
1140     return (fib_table_find_or_create_and_lock_i(proto, table_id,
1141                                                 src, NULL));
1142 }
1143
1144 u32
1145 fib_table_find_or_create_and_lock_w_name (fib_protocol_t proto,
1146                                           u32 table_id,
1147                                           fib_source_t src,
1148                                           const u8 *name)
1149 {
1150     return (fib_table_find_or_create_and_lock_i(proto, table_id,
1151                                                 src, name));
1152 }
1153
1154 u32
1155 fib_table_create_and_lock (fib_protocol_t proto,
1156                            fib_source_t src,
1157                            const char *const fmt,
1158                            ...)
1159 {
1160     fib_table_t *fib_table;
1161     fib_node_index_t fi;
1162     va_list ap;
1163
1164
1165     switch (proto)
1166     {
1167     case FIB_PROTOCOL_IP4:
1168         fi = ip4_fib_table_create_and_lock(src);
1169         break;
1170     case FIB_PROTOCOL_IP6:
1171         fi = ip6_fib_table_create_and_lock(src, FIB_TABLE_FLAG_NONE, NULL);
1172         break;
1173      case FIB_PROTOCOL_MPLS:
1174         fi = mpls_fib_table_create_and_lock(src);
1175         break;
1176    default:
1177         return (~0);        
1178     }
1179
1180     fib_table = fib_table_get(fi, proto);
1181
1182     va_start(ap, fmt);
1183
1184     fib_table->ft_desc = va_format(fib_table->ft_desc, fmt, &ap);
1185
1186     va_end(ap);
1187     return (fi);
1188 }
1189
1190 static void
1191 fib_table_destroy (fib_table_t *fib_table)
1192 {
1193     vec_free(fib_table->ft_desc);
1194
1195     switch (fib_table->ft_proto)
1196     {
1197     case FIB_PROTOCOL_IP4:
1198         ip4_fib_table_destroy(fib_table->ft_index);
1199         break;
1200     case FIB_PROTOCOL_IP6:
1201         ip6_fib_table_destroy(fib_table->ft_index);
1202         break;
1203     case FIB_PROTOCOL_MPLS:
1204         mpls_fib_table_destroy(fib_table->ft_index);
1205         break;
1206     }
1207 }
1208
1209 void
1210 fib_table_walk (u32 fib_index,
1211                 fib_protocol_t proto,
1212                 fib_table_walk_fn_t fn,
1213                 void *ctx)
1214 {
1215     switch (proto)
1216     {
1217     case FIB_PROTOCOL_IP4:
1218         ip4_fib_table_walk(ip4_fib_get(fib_index), fn, ctx);
1219         break;
1220     case FIB_PROTOCOL_IP6:
1221         ip6_fib_table_walk(fib_index, fn, ctx);
1222         break;
1223     case FIB_PROTOCOL_MPLS:
1224         mpls_fib_table_walk(mpls_fib_get(fib_index), fn, ctx);
1225         break;
1226     }
1227 }
1228
1229 void
1230 fib_table_sub_tree_walk (u32 fib_index,
1231                          fib_protocol_t proto,
1232                          const fib_prefix_t *root,
1233                          fib_table_walk_fn_t fn,
1234                          void *ctx)
1235 {
1236     switch (proto)
1237     {
1238     case FIB_PROTOCOL_IP4:
1239         ip4_fib_table_sub_tree_walk(ip4_fib_get(fib_index), root, fn, ctx);
1240         break;
1241     case FIB_PROTOCOL_IP6:
1242         ip6_fib_table_sub_tree_walk(fib_index, root, fn, ctx);
1243         break;
1244     case FIB_PROTOCOL_MPLS:
1245         break;
1246     }
1247 }
1248
1249 void
1250 fib_table_unlock (u32 fib_index,
1251                   fib_protocol_t proto,
1252                   fib_source_t source)
1253 {
1254     fib_table_t *fib_table;
1255
1256     fib_table = fib_table_get(fib_index, proto);
1257     fib_table->ft_locks[source]--;
1258     fib_table->ft_locks[FIB_TABLE_TOTAL_LOCKS]--;
1259
1260     if (0 == fib_table->ft_locks[FIB_TABLE_TOTAL_LOCKS])
1261     {
1262         /*
1263          * no more locak from any source - kill it
1264          */
1265         fib_table_destroy(fib_table);
1266     }
1267 }
1268
1269 void
1270 fib_table_lock (u32 fib_index,
1271                 fib_protocol_t proto,
1272                 fib_source_t source)
1273 {
1274     fib_table_t *fib_table;
1275
1276     fib_table = fib_table_get(fib_index, proto);
1277
1278     ASSERT(fib_table->ft_locks[source] < (0xffff - 1));
1279
1280     fib_table->ft_locks[source]++;
1281     fib_table->ft_locks[FIB_TABLE_TOTAL_LOCKS]++;
1282 }
1283
1284 u32
1285 fib_table_get_num_entries (u32 fib_index,
1286                            fib_protocol_t proto,
1287                            fib_source_t source)
1288 {
1289     fib_table_t *fib_table;
1290
1291     fib_table = fib_table_get(fib_index, proto);
1292
1293     return (fib_table->ft_src_route_counts[source]);
1294 }
1295
1296 u8*
1297 format_fib_table_name (u8* s, va_list* ap)
1298 {
1299     fib_node_index_t fib_index = va_arg(*ap, fib_node_index_t);
1300     fib_protocol_t proto = va_arg(*ap, int); // int promotion
1301     fib_table_t *fib_table;
1302
1303     fib_table = fib_table_get(fib_index, proto);
1304
1305     s = format(s, "%v", fib_table->ft_desc);
1306
1307     return (s);
1308 }
1309
1310 u8*
1311 format_fib_table_flags (u8 *s, va_list *args)
1312 {
1313     fib_table_flags_t flags = va_arg(*args, int);
1314     fib_table_attribute_t attr;
1315
1316     if (!flags)
1317     {
1318         return format(s, "none");
1319     }
1320
1321     FOR_EACH_FIB_TABLE_ATTRIBUTE(attr) {
1322         if (1 << attr & flags) {
1323             s = format(s, "%s", fib_table_flags_strings[attr]);
1324         }
1325     }
1326
1327     return (s);
1328 }
1329
1330 /**
1331  * @brief Table flush context. Store the indicies of matching FIB entries
1332  * that need to be removed.
1333  */
1334 typedef struct fib_table_flush_ctx_t_
1335 {
1336     /**
1337      * The list of entries to flush
1338      */
1339     fib_node_index_t *ftf_entries;
1340
1341     /**
1342      * The source we are flushing
1343      */
1344     fib_source_t ftf_source;
1345 } fib_table_flush_ctx_t;
1346
1347 static fib_table_walk_rc_t
1348 fib_table_flush_cb (fib_node_index_t fib_entry_index,
1349                     void *arg)
1350 {
1351     fib_table_flush_ctx_t *ctx = arg;
1352
1353     if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1354     {
1355         vec_add1(ctx->ftf_entries, fib_entry_index);
1356     }
1357     return (FIB_TABLE_WALK_CONTINUE);
1358 }
1359
1360 void
1361 fib_table_flush (u32 fib_index,
1362                  fib_protocol_t proto,
1363                  fib_source_t source)
1364 {
1365     fib_node_index_t *fib_entry_index;
1366     fib_table_flush_ctx_t ctx = {
1367         .ftf_entries = NULL,
1368         .ftf_source = source,
1369     };
1370
1371     fib_table_walk(fib_index, proto,
1372                    fib_table_flush_cb,
1373                    &ctx);
1374
1375     vec_foreach(fib_entry_index, ctx.ftf_entries)
1376     {
1377         fib_table_entry_delete_index(*fib_entry_index, source);
1378     }
1379
1380     vec_free(ctx.ftf_entries);
1381 }
1382
1383 static fib_table_walk_rc_t
1384 fib_table_mark_cb (fib_node_index_t fib_entry_index,
1385                    void *arg)
1386 {
1387     fib_table_flush_ctx_t *ctx = arg;
1388
1389     if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
1390     {
1391         fib_entry_mark(fib_entry_index, ctx->ftf_source);
1392     }
1393     return (FIB_TABLE_WALK_CONTINUE);
1394 }
1395
1396 void
1397 fib_table_mark (u32 fib_index,
1398                 fib_protocol_t proto,
1399                 fib_source_t source)
1400 {
1401     fib_table_flush_ctx_t ctx = {
1402         .ftf_source = source,
1403     };
1404     fib_table_t *fib_table;
1405
1406     fib_table = fib_table_get(fib_index, proto);
1407
1408     fib_table->ft_epoch++;
1409     fib_table->ft_flags |= FIB_TABLE_FLAG_RESYNC;
1410
1411     fib_table_walk(fib_index, proto,
1412                    fib_table_mark_cb,
1413                    &ctx);
1414 }
1415
1416 static fib_table_walk_rc_t
1417 fib_table_sweep_cb (fib_node_index_t fib_entry_index,
1418                     void *arg)
1419 {
1420     fib_table_flush_ctx_t *ctx = arg;
1421
1422     if (fib_entry_is_marked(fib_entry_index, ctx->ftf_source))
1423     {
1424         vec_add1(ctx->ftf_entries, fib_entry_index);
1425     }
1426     return (FIB_TABLE_WALK_CONTINUE);
1427 }
1428
1429 void
1430 fib_table_sweep (u32 fib_index,
1431                  fib_protocol_t proto,
1432                  fib_source_t source)
1433 {
1434     fib_table_flush_ctx_t ctx = {
1435         .ftf_source = source,
1436     };
1437     fib_node_index_t *fib_entry_index;
1438     fib_table_t *fib_table;
1439
1440     fib_table = fib_table_get(fib_index, proto);
1441
1442     fib_table->ft_flags &= ~FIB_TABLE_FLAG_RESYNC;
1443
1444     fib_table_walk(fib_index, proto,
1445                    fib_table_sweep_cb,
1446                    &ctx);
1447
1448     vec_foreach(fib_entry_index, ctx.ftf_entries)
1449     {
1450         fib_table_entry_delete_index(*fib_entry_index, source);
1451     }
1452
1453     vec_free(ctx.ftf_entries);
1454 }
1455
1456 u8 *
1457 format_fib_table_memory (u8 *s, va_list *args)
1458 {
1459     s = format(s, "%U", format_ip4_fib_table_memory);
1460     s = format(s, "%U", format_ip6_fib_table_memory);
1461     s = format(s, "%U", format_mpls_fib_table_memory);
1462
1463     return (s);
1464 }