Python test IP and MPLS objects conform to infra.
[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,
199                               source,
200                               entry_flags,
201                               INDEX_INVALID))
202         {
203             /*
204              * this update means we can now remove the entry.
205              */
206             mfib_table_entry_remove(mfib_table, prefix, mfib_entry_index);
207         }
208
209         mfib_entry_unlock(mfib_entry_index);
210     }
211
212     return (mfib_entry_index);
213 }
214
215 fib_node_index_t
216 mfib_table_entry_path_update (u32 fib_index,
217                               const mfib_prefix_t *prefix,
218                               mfib_source_t source,
219                               const fib_route_path_t *rpath,
220                               mfib_itf_flags_t itf_flags)
221 {
222     fib_node_index_t mfib_entry_index;
223     mfib_table_t *mfib_table;
224
225     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
226     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
227
228     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
229     {
230         mfib_entry_index = mfib_entry_create(fib_index,
231                                              source,
232                                              prefix,
233                                              MFIB_ENTRY_FLAG_NONE);
234
235         mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
236     }
237
238     mfib_entry_path_update(mfib_entry_index,
239                            source,
240                            rpath,
241                            itf_flags);
242
243     return (mfib_entry_index);
244 }
245
246 void
247 mfib_table_entry_path_remove (u32 fib_index,
248                               const mfib_prefix_t *prefix,
249                               mfib_source_t source,
250                               const fib_route_path_t *rpath)
251 {
252     fib_node_index_t mfib_entry_index;
253     mfib_table_t *mfib_table;
254
255     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
256     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
257
258     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
259     {
260         /*
261          * removing an etry that does not exist. i'll allow it.
262          */
263     }
264     else
265     {
266         int no_more_sources;
267
268         /*
269          * don't nobody go nowhere
270          */
271         mfib_entry_lock(mfib_entry_index);
272
273         no_more_sources = mfib_entry_path_remove(mfib_entry_index,
274                                                  source,
275                                                  rpath);
276
277         if (no_more_sources)
278         {
279             /*
280              * last source gone. remove from the table
281              */
282             mfib_table_entry_remove(mfib_table, prefix, mfib_entry_index);
283         }
284
285         mfib_entry_unlock(mfib_entry_index);
286     }
287 }
288
289 fib_node_index_t
290 mfib_table_entry_special_add (u32 fib_index,
291                               const mfib_prefix_t *prefix,
292                               mfib_source_t source,
293                               mfib_entry_flags_t entry_flags,
294                               index_t rep_dpo)
295 {
296     fib_node_index_t mfib_entry_index;
297     mfib_table_t *mfib_table;
298
299     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
300     mfib_entry_index = mfib_table_lookup_exact_match_i(mfib_table, prefix);
301
302     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
303     {
304         mfib_entry_index = mfib_entry_create(fib_index,
305                                              source,
306                                              prefix,
307                                              MFIB_ENTRY_FLAG_NONE);
308
309         mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
310     }
311
312     mfib_entry_update(mfib_entry_index, source,
313                       (MFIB_ENTRY_FLAG_EXCLUSIVE | entry_flags),
314                       rep_dpo);
315
316     return (mfib_entry_index);
317 }
318
319 static void
320 mfib_table_entry_delete_i (u32 fib_index,
321                            fib_node_index_t mfib_entry_index,
322                            const mfib_prefix_t *prefix,
323                            mfib_source_t source)
324 {
325     mfib_table_t *mfib_table;
326
327     mfib_table = mfib_table_get(fib_index, prefix->fp_proto);
328
329     /*
330      * don't nobody go nowhere
331      */
332     mfib_entry_lock(mfib_entry_index);
333
334     if (mfib_entry_delete(mfib_entry_index, source))
335     {
336         /*
337          * last source gone. remove from the table
338          */
339         mfib_table_entry_remove(mfib_table, prefix, mfib_entry_index);
340     }
341     /*
342      * else
343      *   still has sources, leave it be.
344      */
345
346     mfib_entry_unlock(mfib_entry_index);
347 }
348
349 void
350 mfib_table_entry_delete (u32 fib_index,
351                          const mfib_prefix_t *prefix,
352                          mfib_source_t source)
353 {
354     fib_node_index_t mfib_entry_index;
355
356     mfib_entry_index = mfib_table_lookup_exact_match(fib_index, prefix);
357
358     if (FIB_NODE_INDEX_INVALID == mfib_entry_index)
359     {
360         /*
361          * removing an etry that does not exist.
362          * i'll allow it, but i won't like it.
363          */
364         clib_warning("%U not in FIB", format_mfib_prefix, prefix);
365     }
366     else
367     {
368         mfib_table_entry_delete_i(fib_index, mfib_entry_index,
369                                   prefix, source);
370     }
371 }
372
373 void
374 mfib_table_entry_delete_index (fib_node_index_t mfib_entry_index,
375                                mfib_source_t source)
376 {
377     mfib_prefix_t prefix;
378
379     mfib_entry_get_prefix(mfib_entry_index, &prefix);
380
381     mfib_table_entry_delete_i(mfib_entry_get_fib_index(mfib_entry_index),
382                               mfib_entry_index, &prefix, source);
383 }
384
385 u32
386 mfib_table_get_index_for_sw_if_index (fib_protocol_t proto,
387                                       u32 sw_if_index)
388 {
389     switch (proto)
390     {
391     case FIB_PROTOCOL_IP4:
392         return (ip4_mfib_table_get_index_for_sw_if_index(sw_if_index));
393     case FIB_PROTOCOL_IP6:
394         return (ip6_mfib_table_get_index_for_sw_if_index(sw_if_index));
395     case FIB_PROTOCOL_MPLS:
396         ASSERT(0);
397         break;
398     }
399     return (~0);
400 }
401
402 u32
403 mfib_table_find (fib_protocol_t proto,
404                  u32 table_id)
405 {
406     switch (proto)
407     {
408     case FIB_PROTOCOL_IP4:
409         return (ip4_mfib_index_from_table_id(table_id));
410     case FIB_PROTOCOL_IP6:
411         return (ip6_mfib_index_from_table_id(table_id));
412     case FIB_PROTOCOL_MPLS:
413         ASSERT(0);
414         break;
415     }
416     return (~0);
417 }
418
419 u32
420 mfib_table_find_or_create_and_lock (fib_protocol_t proto,
421                                     u32 table_id)
422 {
423     mfib_table_t *mfib_table;
424     fib_node_index_t fi;
425
426     switch (proto)
427     {
428     case FIB_PROTOCOL_IP4:
429         fi = ip4_mfib_table_find_or_create_and_lock(table_id);
430         break;
431     case FIB_PROTOCOL_IP6:
432         fi = ip6_mfib_table_find_or_create_and_lock(table_id);
433         break;
434     case FIB_PROTOCOL_MPLS:
435     default:
436         return (~0);
437     }
438
439     mfib_table = mfib_table_get(fi, proto);
440
441     mfib_table->mft_desc = format(NULL, "%U-VRF:%d",
442                                   format_fib_protocol, proto,
443                                   table_id);
444
445     return (fi);
446 }
447
448 static void
449 mfib_table_destroy (mfib_table_t *mfib_table)
450 {
451     vec_free(mfib_table->mft_desc);
452
453     switch (mfib_table->mft_proto)
454     {
455     case FIB_PROTOCOL_IP4:
456         ip4_mfib_table_destroy(&mfib_table->v4);
457         break;
458     case FIB_PROTOCOL_IP6:
459         ip6_mfib_table_destroy(&mfib_table->v6);
460         break;
461     case FIB_PROTOCOL_MPLS:
462         ASSERT(0);
463         break;
464     }
465 }
466
467 void
468 mfib_table_unlock (u32 fib_index,
469                    fib_protocol_t proto)
470 {
471     mfib_table_t *mfib_table;
472
473     mfib_table = mfib_table_get(fib_index, proto);
474     mfib_table->mft_locks--;
475
476     if (0 == mfib_table->mft_locks)
477     {
478         mfib_table_destroy(mfib_table);
479     }
480 }
481
482 void
483 mfib_table_lock (u32 fib_index,
484                  fib_protocol_t proto)
485 {
486     mfib_table_t *mfib_table;
487
488     mfib_table = mfib_table_get(fib_index, proto);
489     mfib_table->mft_locks++;
490 }
491
492 void
493 mfib_table_walk (u32 fib_index,
494                  fib_protocol_t proto,
495                  mfib_table_walk_fn_t fn,
496                  void *ctx)
497 {
498     switch (proto)
499     {
500     case FIB_PROTOCOL_IP4:
501         ip4_mfib_table_walk(ip4_mfib_get(fib_index), fn, ctx);
502         break;
503     case FIB_PROTOCOL_IP6:
504         ip6_mfib_table_walk(ip6_mfib_get(fib_index), fn, ctx);
505         break;
506     case FIB_PROTOCOL_MPLS:
507         break;
508     }
509 }
510
511 u8*
512 format_mfib_table_name (u8* s, va_list ap)
513 {
514     fib_node_index_t fib_index = va_arg(ap, fib_node_index_t);
515     fib_protocol_t proto = va_arg(ap, int); // int promotion
516     mfib_table_t *mfib_table;
517
518     mfib_table = mfib_table_get(fib_index, proto);
519
520     s = format(s, "%v", mfib_table->mft_desc);
521
522     return (s);
523 }
524
525 static clib_error_t *
526 mfib_module_init (vlib_main_t * vm)
527 {
528     clib_error_t * error;
529
530     if ((error = vlib_call_init_function (vm, fib_module_init)))
531         return (error);
532     if ((error = vlib_call_init_function (vm, rn_module_init)))
533         return (error);
534
535     mfib_entry_module_init();
536     mfib_signal_module_init();
537
538     return (error);
539 }
540
541 VLIB_INIT_FUNCTION(mfib_module_init);