IP Multicast FIB (mfib)
[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                          mfib_entry_flags_t entry_flags)
169 {
170     fib_node_index_t mfib_entry_index;
171     mfib_table_t *mfib_table;
172
173     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
174     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
175
176     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
177     {
178         if (MFIB_ENTRY_FLAG_NONE != entry_flags)
179         {
180             /*
181              * update to a non-existing entry with non-zero flags
182              */
183             mfib_entry_index = mfib_entry_create(fib_index, source,
184                                                  prefix, entry_flags);
185
186             mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
187         }
188         /*
189          * else
190          *   the entry doesn't exist and the request is to set no flags
191          *   the result would be an entry that doesn't exist - so do nothing
192          */
193     }
194     else
195     {
196         mfib_entry_lock(mfib_entry_index);
197
198         if (mfib_entry_update(mfib_entry_index, source, entry_flags))
199         {
200             /*
201              * this update means we can now remove the entry.
202              */
203             mfib_table_entry_remove(mfib_table, prefix, mfib_entry_index);
204         }
205
206         mfib_entry_unlock(mfib_entry_index);
207     }
208
209     return (mfib_entry_index);
210 }
211
212 fib_node_index_t
213 mfib_table_entry_path_update (u32 fib_index,
214                               const mfib_prefix_t *prefix,
215                               mfib_source_t source,
216                               const fib_route_path_t *rpath,
217                               mfib_itf_flags_t itf_flags)
218 {
219     fib_node_index_t mfib_entry_index;
220     mfib_table_t *mfib_table;
221
222     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
223     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
224
225     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
226     {
227         mfib_entry_index = mfib_entry_create(fib_index,
228                                              source,
229                                              prefix,
230                                              MFIB_ENTRY_FLAG_NONE);
231
232         mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
233     }
234
235     mfib_entry_path_update(mfib_entry_index,
236                            source,
237                            rpath,
238                            itf_flags);
239
240     return (mfib_entry_index);
241 }
242
243 void
244 mfib_table_entry_path_remove (u32 fib_index,
245                               const mfib_prefix_t *prefix,
246                               mfib_source_t source,
247                               const fib_route_path_t *rpath)
248 {
249     fib_node_index_t mfib_entry_index;
250     mfib_table_t *mfib_table;
251
252     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
253     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
254
255     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
256     {
257         /*
258          * removing an etry that does not exist. i'll allow it.
259          */
260     }
261     else
262     {
263         int no_more_sources;
264
265         /*
266          * don't nobody go nowhere
267          */
268         mfib_entry_lock(mfib_entry_index);
269
270         no_more_sources = mfib_entry_path_remove(mfib_entry_index,
271                                                  source,
272                                                  rpath);
273
274         if (no_more_sources)
275         {
276             /*
277              * last source gone. remove from the table
278              */
279             mfib_table_entry_remove(mfib_table, prefix, mfib_entry_index);
280         }
281
282         mfib_entry_unlock(mfib_entry_index);
283     }
284 }
285
286 static void
287 mfib_table_entry_delete_i (u32 fib_index,
288                            fib_node_index_t mfib_entry_index,
289                            const mfib_prefix_t *prefix,
290                            mfib_source_t source)
291 {
292     mfib_table_t *mfib_table;
293
294     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
295
296     /*
297      * don't nobody go nowhere
298      */
299     mfib_entry_lock(mfib_entry_index);
300
301     if (mfib_entry_delete(mfib_entry_index, source))
302     {
303         /*
304          * last source gone. remove from the table
305          */
306         mfib_table_entry_remove(mfib_table, prefix, mfib_entry_index);
307     }
308     /*
309      * else
310      *   still has sources, leave it be.
311      */
312
313     mfib_entry_unlock(mfib_entry_index);
314 }
315
316 void
317 mfib_table_entry_delete (u32 fib_index,
318                          const mfib_prefix_t *prefix,
319                          mfib_source_t source)
320 {
321     fib_node_index_t mfib_entry_index;
322
323     mfib_entry_index = mfib_table_lookup_exact_match(fib_index, prefix);
324
325     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
326     {
327         /*
328          * removing an etry that does not exist.
329          * i'll allow it, but i won't like it.
330          */
331         clib_warning("%U not in FIB", format_mfib_prefix, prefix);
332     }
333     else
334     {
335         mfib_table_entry_delete_i(fib_index, mfib_entry_index,
336                                   prefix, source);
337     }
338 }
339
340 void
341 mfib_table_entry_delete_index (fib_node_index_t mfib_entry_index,
342                                mfib_source_t source)
343 {
344     mfib_prefix_t prefix;
345
346     mfib_entry_get_prefix(mfib_entry_index, &prefix);
347
348     mfib_table_entry_delete_i(mfib_entry_get_fib_index(mfib_entry_index),
349                               mfib_entry_index, &prefix, source);
350 }
351
352 u32
353 mfib_table_get_index_for_sw_if_index (fib_protocol_t proto,
354                                       u32 sw_if_index)
355 {
356     switch (proto)
357     {
358     case FIB_PROTOCOL_IP4:
359         return (ip4_mfib_table_get_index_for_sw_if_index(sw_if_index));
360     case FIB_PROTOCOL_IP6:
361         return (ip6_mfib_table_get_index_for_sw_if_index(sw_if_index));
362     case FIB_PROTOCOL_MPLS:
363         ASSERT(0);
364         break;
365     }
366     return (~0);
367 }
368
369 u32
370 mfib_table_find (fib_protocol_t proto,
371                  u32 table_id)
372 {
373     switch (proto)
374     {
375     case FIB_PROTOCOL_IP4:
376         return (ip4_mfib_index_from_table_id(table_id));
377     case FIB_PROTOCOL_IP6:
378         return (ip6_mfib_index_from_table_id(table_id));
379     case FIB_PROTOCOL_MPLS:
380         ASSERT(0);
381         break;
382     }
383     return (~0);
384 }
385
386 u32
387 mfib_table_find_or_create_and_lock (fib_protocol_t proto,
388                                     u32 table_id)
389 {
390     mfib_table_t *mfib_table;
391     fib_node_index_t fi;
392
393     switch (proto)
394     {
395     case FIB_PROTOCOL_IP4:
396         fi = ip4_mfib_table_find_or_create_and_lock(table_id);
397         break;
398     case FIB_PROTOCOL_IP6:
399         fi = ip6_mfib_table_find_or_create_and_lock(table_id);
400         break;
401     case FIB_PROTOCOL_MPLS:
402     default:
403         return (~0);
404     }
405
406     mfib_table = mfib_table_get(fi, proto);
407
408     mfib_table->mft_desc = format(NULL, "%U-VRF:%d",
409                                   format_fib_protocol, proto,
410                                   table_id);
411
412     return (fi);
413 }
414
415 static void
416 mfib_table_destroy (mfib_table_t *mfib_table)
417 {
418     vec_free(mfib_table->mft_desc);
419
420     switch (mfib_table->mft_proto)
421     {
422     case FIB_PROTOCOL_IP4:
423         ip4_mfib_table_destroy(&mfib_table->v4);
424         break;
425     case FIB_PROTOCOL_IP6:
426         ip6_mfib_table_destroy(&mfib_table->v6);
427         break;
428     case FIB_PROTOCOL_MPLS:
429         ASSERT(0);
430         break;
431     }
432 }
433
434 void
435 mfib_table_unlock (u32 fib_index,
436                    fib_protocol_t proto)
437 {
438     mfib_table_t *mfib_table;
439
440     mfib_table = mfib_table_get(fib_index, proto);
441     mfib_table->mft_locks--;
442
443     if (0 == mfib_table->mft_locks)
444     {
445         mfib_table_destroy(mfib_table);
446     }
447 }
448
449 void
450 mfib_table_lock (u32 fib_index,
451                  fib_protocol_t proto)
452 {
453     mfib_table_t *mfib_table;
454
455     mfib_table = mfib_table_get(fib_index, proto);
456     mfib_table->mft_locks++;
457 }
458
459 u8*
460 format_mfib_table_name (u8* s, va_list ap)
461 {
462     fib_node_index_t fib_index = va_arg(ap, fib_node_index_t);
463     fib_protocol_t proto = va_arg(ap, int); // int promotion
464     mfib_table_t *mfib_table;
465
466     mfib_table = mfib_table_get(fib_index, proto);
467
468     s = format(s, "%v", mfib_table->mft_desc);
469
470     return (s);
471 }
472
473 static clib_error_t *
474 mfib_module_init (vlib_main_t * vm)
475 {
476     clib_error_t * error;
477
478     if ((error = vlib_call_init_function (vm, fib_module_init)))
479         return (error);
480     if ((error = vlib_call_init_function (vm, rn_module_init)))
481         return (error);
482
483     mfib_entry_module_init();
484     mfib_signal_module_init();
485
486     return (error);
487 }
488
489 VLIB_INIT_FUNCTION(mfib_module_init);