Separate heap for IPv4 mtries
[vpp.git] / src / vnet / mfib / mfib_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/mfib/mfib_table.h>
20 #include <vnet/mfib/ip4_mfib.h>
21 #include <vnet/mfib/ip6_mfib.h>
22 #include <vnet/mfib/mfib_entry.h>
23 #include <vnet/mfib/mfib_signal.h>
24
25 mfib_table_t *
26 mfib_table_get (fib_node_index_t index,
27                 fib_protocol_t proto)
28 {
29     switch (proto)
30     {
31     case FIB_PROTOCOL_IP4:
32         return (pool_elt_at_index(ip4_main.mfibs, index));
33     case FIB_PROTOCOL_IP6:
34         return (pool_elt_at_index(ip6_main.mfibs, index));
35     case FIB_PROTOCOL_MPLS:
36         break;
37     }
38     ASSERT(0);
39     return (NULL);
40 }
41
42 static inline fib_node_index_t
43 mfib_table_lookup_i (const mfib_table_t *mfib_table,
44                      const mfib_prefix_t *prefix)
45 {
46     switch (prefix->fp_proto)
47     {
48     case FIB_PROTOCOL_IP4:
49         return (ip4_mfib_table_lookup(&mfib_table->v4,
50                                       &prefix->fp_src_addr.ip4,
51                                       &prefix->fp_grp_addr.ip4,
52                                       prefix->fp_len));
53     case FIB_PROTOCOL_IP6:
54         return (ip6_mfib_table_lookup(&mfib_table->v6,
55                                       &prefix->fp_src_addr.ip6,
56                                       &prefix->fp_grp_addr.ip6,
57                                       prefix->fp_len));
58     case FIB_PROTOCOL_MPLS:
59         break;
60     }
61     return (FIB_NODE_INDEX_INVALID);
62 }
63
64 fib_node_index_t
65 mfib_table_lookup (u32 fib_index,
66                    const mfib_prefix_t *prefix)
67 {
68     return (mfib_table_lookup_i(mfib_table_get(fib_index, prefix->fp_proto), prefix));
69 }
70
71 static inline fib_node_index_t
72 mfib_table_lookup_exact_match_i (const mfib_table_t *mfib_table,
73                                  const mfib_prefix_t *prefix)
74 {
75     switch (prefix->fp_proto)
76     {
77     case FIB_PROTOCOL_IP4:
78         return (ip4_mfib_table_lookup_exact_match(&mfib_table->v4,
79                                                   &prefix->fp_grp_addr.ip4,
80                                                   &prefix->fp_src_addr.ip4,
81                                                   prefix->fp_len));
82     case FIB_PROTOCOL_IP6:
83         return (ip6_mfib_table_lookup_exact_match(&mfib_table->v6,
84                                                   &prefix->fp_grp_addr.ip6,
85                                                   &prefix->fp_src_addr.ip6,
86                                                   prefix->fp_len));
87     case FIB_PROTOCOL_MPLS:
88         break;
89     }
90     return (FIB_NODE_INDEX_INVALID);
91 }
92
93 fib_node_index_t
94 mfib_table_lookup_exact_match (u32 fib_index,
95                               const mfib_prefix_t *prefix)
96 {
97     return (mfib_table_lookup_exact_match_i(mfib_table_get(fib_index,
98                                                           prefix->fp_proto),
99                                             prefix));
100 }
101
102 static void
103 mfib_table_entry_remove (mfib_table_t *mfib_table,
104                          const mfib_prefix_t *prefix,
105                          fib_node_index_t fib_entry_index)
106 {
107     vlib_smp_unsafe_warning();
108
109     mfib_table->mft_total_route_counts--;
110
111     switch (prefix->fp_proto)
112     {
113     case FIB_PROTOCOL_IP4:
114         ip4_mfib_table_entry_remove(&mfib_table->v4,
115                                     &prefix->fp_grp_addr.ip4,
116                                     &prefix->fp_src_addr.ip4,
117                                     prefix->fp_len);
118         break;
119     case FIB_PROTOCOL_IP6:
120         ip6_mfib_table_entry_remove(&mfib_table->v6,
121                                     &prefix->fp_grp_addr.ip6,
122                                     &prefix->fp_src_addr.ip6,
123                                     prefix->fp_len);
124         break;
125     case FIB_PROTOCOL_MPLS:
126         ASSERT(0);
127         break;
128     }
129
130     mfib_entry_unlock(fib_entry_index);
131 }
132
133 static void
134 mfib_table_entry_insert (mfib_table_t *mfib_table,
135                          const mfib_prefix_t *prefix,
136                          fib_node_index_t mfib_entry_index)
137 {
138     vlib_smp_unsafe_warning();
139
140     mfib_entry_lock(mfib_entry_index);
141     mfib_table->mft_total_route_counts++;
142
143     switch (prefix->fp_proto)
144     {
145     case FIB_PROTOCOL_IP4:
146         ip4_mfib_table_entry_insert(&mfib_table->v4,
147                                     &prefix->fp_grp_addr.ip4,
148                                     &prefix->fp_src_addr.ip4,
149                                     prefix->fp_len,
150                                     mfib_entry_index);
151         break;
152     case FIB_PROTOCOL_IP6:
153         ip6_mfib_table_entry_insert(&mfib_table->v6,
154                                     &prefix->fp_grp_addr.ip6,
155                                     &prefix->fp_src_addr.ip6,
156                                     prefix->fp_len,
157                                     mfib_entry_index);
158         break;
159     case FIB_PROTOCOL_MPLS:
160         break;
161     }
162 }
163
164 fib_node_index_t
165 mfib_table_entry_update (u32 fib_index,
166                          const mfib_prefix_t *prefix,
167                          mfib_source_t source,
168                          fib_rpf_id_t rpf_id,
169                          mfib_entry_flags_t entry_flags)
170 {
171     fib_node_index_t mfib_entry_index;
172     mfib_table_t *mfib_table;
173
174     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
175     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
176
177     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
178     {
179         if (MFIB_ENTRY_FLAG_NONE != entry_flags)
180         {
181             /*
182              * update to a non-existing entry with non-zero flags
183              */
184             mfib_entry_index = mfib_entry_create(fib_index, source,
185                                                  prefix, rpf_id,
186                                                  entry_flags);
187
188             mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
189         }
190         /*
191          * else
192          *   the entry doesn't exist and the request is to set no flags
193          *   the result would be an entry that doesn't exist - so do nothing
194          */
195     }
196     else
197     {
198         mfib_entry_lock(mfib_entry_index);
199
200         if (mfib_entry_update(mfib_entry_index,
201                               source,
202                               entry_flags,
203                               rpf_id,
204                               INDEX_INVALID))
205         {
206             /*
207              * this update means we can now remove the entry.
208              */
209             mfib_table_entry_remove(mfib_table, prefix, mfib_entry_index);
210         }
211
212         mfib_entry_unlock(mfib_entry_index);
213     }
214
215     return (mfib_entry_index);
216 }
217
218 fib_node_index_t
219 mfib_table_entry_path_update (u32 fib_index,
220                               const mfib_prefix_t *prefix,
221                               mfib_source_t source,
222                               const fib_route_path_t *rpath,
223                               mfib_itf_flags_t itf_flags)
224 {
225     fib_node_index_t mfib_entry_index;
226     mfib_table_t *mfib_table;
227
228     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
229     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
230
231     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
232     {
233         mfib_entry_index = mfib_entry_create(fib_index,
234                                              source,
235                                              prefix,
236                                              MFIB_RPF_ID_NONE,
237                                              MFIB_ENTRY_FLAG_NONE);
238
239         mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
240     }
241
242     mfib_entry_path_update(mfib_entry_index,
243                            source,
244                            rpath,
245                            itf_flags);
246
247     return (mfib_entry_index);
248 }
249
250 void
251 mfib_table_entry_path_remove (u32 fib_index,
252                               const mfib_prefix_t *prefix,
253                               mfib_source_t source,
254                               const fib_route_path_t *rpath)
255 {
256     fib_node_index_t mfib_entry_index;
257     mfib_table_t *mfib_table;
258
259     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
260     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
261
262     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
263     {
264         /*
265          * removing an etry that does not exist. i'll allow it.
266          */
267     }
268     else
269     {
270         int no_more_sources;
271
272         /*
273          * don't nobody go nowhere
274          */
275         mfib_entry_lock(mfib_entry_index);
276
277         no_more_sources = mfib_entry_path_remove(mfib_entry_index,
278                                                  source,
279                                                  rpath);
280
281         if (no_more_sources)
282         {
283             /*
284              * last source gone. remove from the table
285              */
286             mfib_table_entry_remove(mfib_table, prefix, mfib_entry_index);
287         }
288
289         mfib_entry_unlock(mfib_entry_index);
290     }
291 }
292
293 fib_node_index_t
294 mfib_table_entry_special_add (u32 fib_index,
295                               const mfib_prefix_t *prefix,
296                               mfib_source_t source,
297                               mfib_entry_flags_t entry_flags,
298                               index_t rep_dpo)
299 {
300     fib_node_index_t mfib_entry_index;
301     mfib_table_t *mfib_table;
302
303     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
304     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
305
306     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
307     {
308         mfib_entry_index = mfib_entry_create(fib_index,
309                                              source,
310                                              prefix,
311                                              MFIB_RPF_ID_NONE,
312                                              MFIB_ENTRY_FLAG_NONE);
313
314         mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
315     }
316
317     mfib_entry_update(mfib_entry_index, source,
318                       (MFIB_ENTRY_FLAG_EXCLUSIVE | entry_flags),
319                       MFIB_RPF_ID_NONE,
320                       rep_dpo);
321
322     return (mfib_entry_index);
323 }
324
325 static void
326 mfib_table_entry_delete_i (u32 fib_index,
327                            fib_node_index_t mfib_entry_index,
328                            const mfib_prefix_t *prefix,
329                            mfib_source_t source)
330 {
331     mfib_table_t *mfib_table;
332
333     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
334
335     /*
336      * don't nobody go nowhere
337      */
338     mfib_entry_lock(mfib_entry_index);
339
340     if (mfib_entry_delete(mfib_entry_index, source))
341     {
342         /*
343          * last source gone. remove from the table
344          */
345         mfib_table_entry_remove(mfib_table, prefix, mfib_entry_index);
346     }
347     /*
348      * else
349      *   still has sources, leave it be.
350      */
351
352     mfib_entry_unlock(mfib_entry_index);
353 }
354
355 void
356 mfib_table_entry_delete (u32 fib_index,
357                          const mfib_prefix_t *prefix,
358                          mfib_source_t source)
359 {
360     fib_node_index_t mfib_entry_index;
361
362     mfib_entry_index = mfib_table_lookup_exact_match(fib_index, prefix);
363
364     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
365     {
366         /*
367          * removing an etry that does not exist.
368          * i'll allow it, but i won't like it.
369          */
370         clib_warning("%U not in FIB", format_mfib_prefix, prefix);
371     }
372     else
373     {
374         mfib_table_entry_delete_i(fib_index, mfib_entry_index,
375                                   prefix, source);
376     }
377 }
378
379 void
380 mfib_table_entry_delete_index (fib_node_index_t mfib_entry_index,
381                                mfib_source_t source)
382 {
383     mfib_prefix_t prefix;
384
385     mfib_entry_get_prefix(mfib_entry_index, &prefix);
386
387     mfib_table_entry_delete_i(mfib_entry_get_fib_index(mfib_entry_index),
388                               mfib_entry_index, &prefix, source);
389 }
390
391 u32
392 mfib_table_get_index_for_sw_if_index (fib_protocol_t proto,
393                                       u32 sw_if_index)
394 {
395     switch (proto)
396     {
397     case FIB_PROTOCOL_IP4:
398         return (ip4_mfib_table_get_index_for_sw_if_index(sw_if_index));
399     case FIB_PROTOCOL_IP6:
400         return (ip6_mfib_table_get_index_for_sw_if_index(sw_if_index));
401     case FIB_PROTOCOL_MPLS:
402         ASSERT(0);
403         break;
404     }
405     return (~0);
406 }
407
408 u32
409 mfib_table_find (fib_protocol_t proto,
410                  u32 table_id)
411 {
412     switch (proto)
413     {
414     case FIB_PROTOCOL_IP4:
415         return (ip4_mfib_index_from_table_id(table_id));
416     case FIB_PROTOCOL_IP6:
417         return (ip6_mfib_index_from_table_id(table_id));
418     case FIB_PROTOCOL_MPLS:
419         ASSERT(0);
420         break;
421     }
422     return (~0);
423 }
424
425 static u32
426 mfib_table_find_or_create_and_lock_i (fib_protocol_t proto,
427                                       u32 table_id,
428                                       mfib_source_t src,
429                                       const u8 *name)
430 {
431     mfib_table_t *mfib_table;
432     fib_node_index_t fi;
433
434     switch (proto)
435     {
436     case FIB_PROTOCOL_IP4:
437         fi = ip4_mfib_table_find_or_create_and_lock(table_id, src);
438         break;
439     case FIB_PROTOCOL_IP6:
440         fi = ip6_mfib_table_find_or_create_and_lock(table_id, src);
441         break;
442     case FIB_PROTOCOL_MPLS:
443     default:
444         return (~0);
445     }
446
447     mfib_table = mfib_table_get(fi, proto);
448
449     if (NULL == mfib_table->mft_desc)
450     {
451         if (name && name[0])
452         {
453             mfib_table->mft_desc = format(NULL, "%s", name);
454         }
455         else
456         {
457             mfib_table->mft_desc = format(NULL, "%U-VRF:%d",
458                                           format_fib_protocol, proto,
459                                           table_id);
460         }
461     }
462
463     return (fi);
464 }
465
466 u32
467 mfib_table_find_or_create_and_lock (fib_protocol_t proto,
468                                     u32 table_id,
469                                     mfib_source_t src)
470 {
471     return (mfib_table_find_or_create_and_lock_i(proto, table_id,
472                                                  src, NULL));
473 }
474
475 u32
476 mfib_table_find_or_create_and_lock_w_name (fib_protocol_t proto,
477                                            u32 table_id,
478                                            mfib_source_t src,
479                                            const u8 *name)
480 {
481     return (mfib_table_find_or_create_and_lock_i(proto, table_id,
482                                                  src, name));
483 }
484
485 /**
486  * @brief Table flush context. Store the indicies of matching FIB entries
487  * that need to be removed.
488  */
489 typedef struct mfib_table_flush_ctx_t_
490 {
491     /**
492      * The list of entries to flush
493      */
494     fib_node_index_t *mftf_entries;
495
496     /**
497      * The source we are flushing
498      */
499     mfib_source_t mftf_source;
500 } mfib_table_flush_ctx_t;
501
502 static int
503 mfib_table_flush_cb (fib_node_index_t mfib_entry_index,
504                      void *arg)
505 {
506     mfib_table_flush_ctx_t *ctx = arg;
507
508     if (mfib_entry_is_sourced(mfib_entry_index, ctx->mftf_source))
509     {
510         vec_add1(ctx->mftf_entries, mfib_entry_index);
511     }
512     return (1);
513 }
514
515 void
516 mfib_table_flush (u32 mfib_index,
517                   fib_protocol_t proto,
518                   mfib_source_t source)
519 {
520     fib_node_index_t *mfib_entry_index;
521     mfib_table_flush_ctx_t ctx = {
522         .mftf_entries = NULL,
523         .mftf_source = source,
524     };
525
526     mfib_table_walk(mfib_index, proto,
527                     mfib_table_flush_cb,
528                     &ctx);
529
530     vec_foreach(mfib_entry_index, ctx.mftf_entries)
531     {
532         mfib_table_entry_delete_index(*mfib_entry_index, source);
533     }
534
535     vec_free(ctx.mftf_entries);
536 }
537
538 static void
539 mfib_table_destroy (mfib_table_t *mfib_table)
540 {
541     vec_free(mfib_table->mft_desc);
542
543     switch (mfib_table->mft_proto)
544     {
545     case FIB_PROTOCOL_IP4:
546         ip4_mfib_table_destroy(&mfib_table->v4);
547         break;
548     case FIB_PROTOCOL_IP6:
549         ip6_mfib_table_destroy(&mfib_table->v6);
550         break;
551     case FIB_PROTOCOL_MPLS:
552         ASSERT(0);
553         break;
554     }
555 }
556
557 void
558 mfib_table_unlock (u32 fib_index,
559                    fib_protocol_t proto,
560                    mfib_source_t source)
561 {
562     mfib_table_t *mfib_table;
563
564     mfib_table = mfib_table_get(fib_index, proto);
565     mfib_table->mft_locks[source]--;
566     mfib_table->mft_locks[MFIB_TABLE_TOTAL_LOCKS]--;
567
568     if (0 == mfib_table->mft_locks[source])
569     {
570         /*
571          * The source no longer needs the table. flush any routes
572          * from it just in case
573          */
574         mfib_table_flush(fib_index, proto, source);
575     }
576
577     if (0 == mfib_table->mft_locks[MFIB_TABLE_TOTAL_LOCKS])
578     {
579         /*
580          * no more locak from any source - kill it
581          */
582         mfib_table_destroy(mfib_table);
583     }
584 }
585
586 void
587 mfib_table_lock (u32 fib_index,
588                  fib_protocol_t proto,
589                  mfib_source_t source)
590 {
591     mfib_table_t *mfib_table;
592
593     mfib_table = mfib_table_get(fib_index, proto);
594     mfib_table->mft_locks[source]++;
595     mfib_table->mft_locks[MFIB_TABLE_TOTAL_LOCKS]++;
596 }
597
598 void
599 mfib_table_walk (u32 fib_index,
600                  fib_protocol_t proto,
601                  mfib_table_walk_fn_t fn,
602                  void *ctx)
603 {
604     switch (proto)
605     {
606     case FIB_PROTOCOL_IP4:
607         ip4_mfib_table_walk(ip4_mfib_get(fib_index), fn, ctx);
608         break;
609     case FIB_PROTOCOL_IP6:
610         ip6_mfib_table_walk(ip6_mfib_get(fib_index), fn, ctx);
611         break;
612     case FIB_PROTOCOL_MPLS:
613         break;
614     }
615 }
616
617 u8*
618 format_mfib_table_name (u8* s, va_list *ap)
619 {
620     fib_node_index_t fib_index = va_arg(*ap, fib_node_index_t);
621     fib_protocol_t proto = va_arg(*ap, int); // int promotion
622     mfib_table_t *mfib_table;
623
624     mfib_table = mfib_table_get(fib_index, proto);
625
626     s = format(s, "%v", mfib_table->mft_desc);
627
628     return (s);
629 }
630
631 u8 *
632 format_mfib_table_memory (u8 *s, va_list *args)
633 {
634     s = format(s, "%U", format_ip4_mfib_table_memory);
635     s = format(s, "%U", format_ip6_mfib_table_memory);
636
637     return (s);
638 }
639
640 static clib_error_t *
641 mfib_module_init (vlib_main_t * vm)
642 {
643     clib_error_t * error;
644
645     mfib_entry_module_init();
646     mfib_signal_module_init();
647
648     if ((error = vlib_call_init_function (vm, fib_module_init)))
649         return (error);
650     if ((error = vlib_call_init_function (vm, rn_module_init)))
651         return (error);
652
653     return (error);
654 }
655
656 VLIB_INIT_FUNCTION(mfib_module_init);