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