MPLS Mcast
[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 u32
426 mfib_table_find_or_create_and_lock (fib_protocol_t proto,
427                                     u32 table_id)
428 {
429     mfib_table_t *mfib_table;
430     fib_node_index_t fi;
431
432     switch (proto)
433     {
434     case FIB_PROTOCOL_IP4:
435         fi = ip4_mfib_table_find_or_create_and_lock(table_id);
436         break;
437     case FIB_PROTOCOL_IP6:
438         fi = ip6_mfib_table_find_or_create_and_lock(table_id);
439         break;
440     case FIB_PROTOCOL_MPLS:
441     default:
442         return (~0);
443     }
444
445     mfib_table = mfib_table_get(fi, proto);
446
447     mfib_table->mft_desc = format(NULL, "%U-VRF:%d",
448                                   format_fib_protocol, proto,
449                                   table_id);
450
451     return (fi);
452 }
453
454 static void
455 mfib_table_destroy (mfib_table_t *mfib_table)
456 {
457     vec_free(mfib_table->mft_desc);
458
459     switch (mfib_table->mft_proto)
460     {
461     case FIB_PROTOCOL_IP4:
462         ip4_mfib_table_destroy(&mfib_table->v4);
463         break;
464     case FIB_PROTOCOL_IP6:
465         ip6_mfib_table_destroy(&mfib_table->v6);
466         break;
467     case FIB_PROTOCOL_MPLS:
468         ASSERT(0);
469         break;
470     }
471 }
472
473 void
474 mfib_table_unlock (u32 fib_index,
475                    fib_protocol_t proto)
476 {
477     mfib_table_t *mfib_table;
478
479     mfib_table = mfib_table_get(fib_index, proto);
480     mfib_table->mft_locks--;
481
482     if (0 == mfib_table->mft_locks)
483     {
484         mfib_table_destroy(mfib_table);
485     }
486 }
487
488 void
489 mfib_table_lock (u32 fib_index,
490                  fib_protocol_t proto)
491 {
492     mfib_table_t *mfib_table;
493
494     mfib_table = mfib_table_get(fib_index, proto);
495     mfib_table->mft_locks++;
496 }
497
498 void
499 mfib_table_walk (u32 fib_index,
500                  fib_protocol_t proto,
501                  mfib_table_walk_fn_t fn,
502                  void *ctx)
503 {
504     switch (proto)
505     {
506     case FIB_PROTOCOL_IP4:
507         ip4_mfib_table_walk(ip4_mfib_get(fib_index), fn, ctx);
508         break;
509     case FIB_PROTOCOL_IP6:
510         ip6_mfib_table_walk(ip6_mfib_get(fib_index), fn, ctx);
511         break;
512     case FIB_PROTOCOL_MPLS:
513         break;
514     }
515 }
516
517 u8*
518 format_mfib_table_name (u8* s, va_list ap)
519 {
520     fib_node_index_t fib_index = va_arg(ap, fib_node_index_t);
521     fib_protocol_t proto = va_arg(ap, int); // int promotion
522     mfib_table_t *mfib_table;
523
524     mfib_table = mfib_table_get(fib_index, proto);
525
526     s = format(s, "%v", mfib_table->mft_desc);
527
528     return (s);
529 }
530
531 static clib_error_t *
532 mfib_module_init (vlib_main_t * vm)
533 {
534     clib_error_t * error;
535
536     if ((error = vlib_call_init_function (vm, fib_module_init)))
537         return (error);
538     if ((error = vlib_call_init_function (vm, rn_module_init)))
539         return (error);
540
541     mfib_entry_module_init();
542     mfib_signal_module_init();
543
544     return (error);
545 }
546
547 VLIB_INIT_FUNCTION(mfib_module_init);