fib: doc nitfixes
[vpp.git] / src / vnet / mfib / ip4_mfib.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 <vnet/mfib/ip4_mfib.h>
17
18 #include <vnet/mfib/mfib_table.h>
19 #include <vnet/mfib/mfib_entry.h>
20
21 static const mfib_prefix_t all_zeros =
22 {
23     .fp_proto = FIB_PROTOCOL_IP4,
24 };
25 static const mfib_prefix_t ip4_specials[] =
26 {
27     /* ALL prefixes are in network order */
28     {
29         /* (*,224.0.0.1)/32 - all hosts */
30         .fp_grp_addr = {
31             .ip4.data_u32 = 0x010000e0,
32         },
33         .fp_len = 32,
34         .fp_proto = FIB_PROTOCOL_IP4,
35     },
36     {
37         /* (*,224.0.0.2)/32 - all routers */
38         .fp_grp_addr = {
39             .ip4.data_u32 = 0x020000e0,
40         },
41         .fp_len = 32,
42         .fp_proto = FIB_PROTOCOL_IP4,
43     },
44 };
45
46 static u32
47 ip4_create_mfib_with_table_id (u32 table_id,
48                                mfib_source_t src)
49 {
50     mfib_table_t *mfib_table;
51
52     pool_get_aligned(ip4_main.mfibs, mfib_table, CLIB_CACHE_LINE_BYTES);
53     clib_memset(mfib_table, 0, sizeof(*mfib_table));
54
55     mfib_table->mft_proto = FIB_PROTOCOL_IP4;
56     mfib_table->mft_index =
57         mfib_table->v4.index =
58             (mfib_table - ip4_main.mfibs);
59
60     hash_set (ip4_main.mfib_index_by_table_id,
61               table_id,
62               mfib_table->mft_index);
63
64     mfib_table->mft_table_id =
65         mfib_table->v4.table_id =
66             table_id;
67
68     mfib_table_lock(mfib_table->mft_index, FIB_PROTOCOL_IP4, src);
69
70     /*
71      * add the default route into the new FIB
72      */
73     mfib_table_entry_update(mfib_table->mft_index,
74                             &all_zeros,
75                             MFIB_SOURCE_DEFAULT_ROUTE,
76                             MFIB_RPF_ID_NONE,
77                             MFIB_ENTRY_FLAG_DROP);
78
79     const fib_route_path_t path = {
80         .frp_proto = DPO_PROTO_IP4,
81         .frp_addr = zero_addr,
82         .frp_sw_if_index = ~0,
83         .frp_fib_index = ~0,
84         .frp_weight = 1,
85         .frp_flags = FIB_ROUTE_PATH_LOCAL,
86         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
87     };
88     int ii;
89
90     for (ii = 0; ii < ARRAY_LEN(ip4_specials); ii++)
91     {
92         mfib_table_entry_path_update(mfib_table->mft_index,
93                                      &ip4_specials[ii],
94                                      MFIB_SOURCE_SPECIAL,
95                                      &path);
96     }
97
98     return (mfib_table->mft_index);
99 }
100
101 void
102 ip4_mfib_table_destroy (ip4_mfib_t *mfib)
103 {
104     mfib_table_t *mfib_table = (mfib_table_t*)mfib;
105     int ii;
106
107     /*
108      * remove all the specials we added when the table was created.
109      */
110     mfib_table_entry_delete(mfib_table->mft_index,
111                             &all_zeros,
112                             MFIB_SOURCE_DEFAULT_ROUTE);
113
114     for (ii = 0; ii < ARRAY_LEN(ip4_specials); ii++)
115     {
116         mfib_table_entry_delete(mfib_table->mft_index,
117                                 &ip4_specials[ii],
118                                 MFIB_SOURCE_SPECIAL);
119     }
120
121     /*
122      * validate no more routes.
123      */
124     ASSERT(0 == mfib_table->mft_total_route_counts);
125     ASSERT(~0 != mfib_table->mft_table_id);
126
127     hash_unset (ip4_main.mfib_index_by_table_id, mfib_table->mft_table_id);
128     pool_put(ip4_main.mfibs, mfib_table);
129 }
130
131 void
132 ip4_mfib_interface_enable_disable (u32 sw_if_index, int is_enable)
133 {
134     const fib_route_path_t path = {
135         .frp_proto = DPO_PROTO_IP4,
136         .frp_addr = zero_addr,
137         .frp_sw_if_index = sw_if_index,
138         .frp_fib_index = ~0,
139         .frp_weight = 1,
140         .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
141     };
142     u32 mfib_index;
143     int ii;
144
145     mfib_index = ip4_mfib_table_get_index_for_sw_if_index(sw_if_index);
146
147     for (ii = 0; ii < ARRAY_LEN(ip4_specials); ii++)
148     {
149         if (is_enable)
150         {
151             mfib_table_entry_path_update(mfib_index,
152                                          &ip4_specials[ii],
153                                          MFIB_SOURCE_SPECIAL,
154                                          &path);
155         }
156         else
157         {
158             mfib_table_entry_path_remove(mfib_index,
159                                          &ip4_specials[ii],
160                                          MFIB_SOURCE_SPECIAL,
161                                          &path);
162         }
163     }
164 }
165
166 u32
167 ip4_mfib_table_find_or_create_and_lock (u32 table_id,
168                                         mfib_source_t src)
169 {
170     u32 index;
171
172     index = ip4_mfib_index_from_table_id(table_id);
173     if (~0 == index)
174         return ip4_create_mfib_with_table_id(table_id, src);
175     mfib_table_lock(index, FIB_PROTOCOL_IP4, src);
176
177     return (index);
178 }
179
180 u32
181 ip4_mfib_table_get_index_for_sw_if_index (u32 sw_if_index)
182 {
183     if (sw_if_index >= vec_len(ip4_main.mfib_index_by_sw_if_index))
184     {
185         /*
186          * This is the case for interfaces that are not yet mapped to
187          * a IP table
188          */
189         return (~0);
190     }
191     return (ip4_main.mfib_index_by_sw_if_index[sw_if_index]);
192 }
193
194 #define IPV4_MFIB_GRP_LEN(_len)\
195     (_len > 32 ? 32 : _len)
196
197 #define IP4_MFIB_MK_KEY(_grp, _src, _len, _key)                         \
198 {                                                                       \
199     _key  = ((u64)(_grp->data_u32 &                                     \
200                    ip4_main.fib_masks[IPV4_MFIB_GRP_LEN(_len)])) << 32; \
201     _key |= _src->data_u32;                                             \
202 }
203 #define IP4_MFIB_MK_GRP_KEY(_grp, _len, _key)                           \
204 {                                                                       \
205     _key  = ((u64)(_grp->data_u32 &                                     \
206                    ip4_main.fib_masks[IPV4_MFIB_GRP_LEN(_len)])) << 32; \
207 }
208
209 /*
210  * ip4_fib_table_lookup_exact_match
211  *
212  * Exact match prefix lookup
213  */
214 fib_node_index_t
215 ip4_mfib_table_lookup_exact_match (const ip4_mfib_t *mfib,
216                                    const ip4_address_t *grp,
217                                    const ip4_address_t *src,
218                                    u32 len)
219 {
220     uword * hash, * result;
221     u64 key;
222
223     hash = mfib->fib_entry_by_dst_address[len];
224     IP4_MFIB_MK_KEY(grp, src, len, key);
225
226     result = hash_get(hash, key);
227
228     if (NULL != result) {
229         return (result[0]);
230     }
231     return (FIB_NODE_INDEX_INVALID);
232 }
233
234 /*
235  * ip4_fib_table_lookup
236  *
237  * Longest prefix match
238  */
239 fib_node_index_t
240 ip4_mfib_table_lookup (const ip4_mfib_t *mfib,
241                        const ip4_address_t *src,
242                        const ip4_address_t *grp,
243                        u32 len)
244 {
245     uword * hash, * result;
246     i32 mask_len;
247     u64 key;
248
249     mask_len = len;
250
251     if (PREDICT_TRUE(64 == mask_len))
252     {
253         hash = mfib->fib_entry_by_dst_address[mask_len];
254         IP4_MFIB_MK_KEY(grp, src, mask_len, key);
255
256         result = hash_get (hash, key);
257
258         if (NULL != result) {
259             return (result[0]);
260         }
261     }
262
263     for (mask_len = (len == 64 ? 32 : len); mask_len >= 0; mask_len--)
264     {
265         hash = mfib->fib_entry_by_dst_address[mask_len];
266         IP4_MFIB_MK_GRP_KEY(grp, mask_len, key);
267
268         result = hash_get (hash, key);
269
270         if (NULL != result) {
271             return (result[0]);
272         }
273     }
274     return (FIB_NODE_INDEX_INVALID);
275 }
276
277 fib_node_index_t
278 ip4_mfib_table_get_less_specific (const ip4_mfib_t *mfib,
279                                   const ip4_address_t *src,
280                                   const ip4_address_t *grp,
281                                   u32 len)
282 {
283     u32 mask_len;
284
285     /*
286      * in the absence of a tree structure for the table that allows for an O(1)
287      * parent get, a cheeky way to find the cover is to LPM for the prefix with
288      * mask-1.
289      * there should always be a cover, though it may be the default route. the
290      * default route's cover is the default route.
291      */
292     if (len == 64)
293     {
294         /* go from (S,G) to (*,G*) */
295         mask_len = 32;
296     }
297     else if (len != 0)
298     {
299         mask_len = len - 1;
300     }
301     else
302     {
303         mask_len = len;
304     }
305
306     return (ip4_mfib_table_lookup(mfib, src, grp, mask_len));
307 }
308
309 void
310 ip4_mfib_table_entry_insert (ip4_mfib_t *mfib,
311                              const ip4_address_t *grp,
312                              const ip4_address_t *src,
313                              u32 len,
314                              fib_node_index_t fib_entry_index)
315 {
316     uword * hash, * result;
317     u64 key;
318
319     IP4_MFIB_MK_KEY(grp, src, len, key);
320     hash = mfib->fib_entry_by_dst_address[len];
321     result = hash_get (hash, key);
322
323     if (NULL == result) {
324         /*
325          * adding a new entry
326          */
327         if (NULL == hash) {
328             hash = hash_create (32 /* elts */, sizeof (uword));
329             hash_set_flags (hash, HASH_FLAG_NO_AUTO_SHRINK);
330         }
331         hash = hash_set(hash, key, fib_entry_index);
332         mfib->fib_entry_by_dst_address[len] = hash;
333     }
334     else
335     {
336         ASSERT(0);
337     }
338 }
339
340 void
341 ip4_mfib_table_entry_remove (ip4_mfib_t *mfib,
342                              const ip4_address_t *grp,
343                              const ip4_address_t *src,
344                              u32 len)
345 {
346     uword * hash, * result;
347     u64 key;
348
349     IP4_MFIB_MK_KEY(grp, src, len, key);
350     hash = mfib->fib_entry_by_dst_address[len];
351     result = hash_get (hash, key);
352
353     if (NULL == result)
354     {
355         /*
356          * removing a non-existent entry. i'll allow it.
357          */
358     }
359     else
360     {
361         hash_unset(hash, key);
362     }
363
364     mfib->fib_entry_by_dst_address[len] = hash;
365 }
366
367 void
368 ip4_mfib_table_walk (ip4_mfib_t *mfib,
369                      mfib_table_walk_fn_t fn,
370                      void *ctx)
371 {
372     int i;
373
374     for (i = 0; i < ARRAY_LEN (mfib->fib_entry_by_dst_address); i++)
375     {
376         uword * hash = mfib->fib_entry_by_dst_address[i];
377
378         if (NULL != hash)
379         {
380             hash_pair_t * p;
381
382             hash_foreach_pair (p, hash,
383             ({
384                 fn(p->value[0], ctx);
385             }));
386         }
387     }
388 }
389
390 u8 *
391 format_ip4_mfib_table_memory (u8 * s, va_list * args)
392 {
393     mfib_table_t *mfib_table;
394     u64 total_memory;
395
396     total_memory = 0;
397
398     pool_foreach (mfib_table, ip4_main.mfibs)
399      {
400         ip4_mfib_t *mfib = &mfib_table->v4;
401         uword mfib_size;
402         int i;
403
404         mfib_size = 0;
405
406         for (i = 0; i < ARRAY_LEN (mfib->fib_entry_by_dst_address); i++)
407         {
408             uword * hash = mfib->fib_entry_by_dst_address[i];
409
410             if (NULL != hash)
411             {
412                 mfib_size += hash_bytes(hash);
413             }
414         }
415
416         total_memory += mfib_size;
417     }
418
419     s = format(s, "%=30s %=6d %=12ld\n",
420                "IPv4 multicast",
421                pool_elts(ip4_main.mfibs), total_memory);
422
423     return (s);
424 }
425
426 static void
427 ip4_mfib_table_show_all (ip4_mfib_t *mfib,
428                          vlib_main_t * vm)
429 {
430     fib_node_index_t *mfib_entry_indicies;
431     fib_node_index_t *mfib_entry_index;
432     int i;
433
434     mfib_entry_indicies = NULL;
435
436     for (i = 0; i < ARRAY_LEN (mfib->fib_entry_by_dst_address); i++)
437     {
438         uword * hash = mfib->fib_entry_by_dst_address[i];
439
440         if (NULL != hash)
441         {
442             hash_pair_t * p;
443
444             hash_foreach_pair (p, hash,
445             ({
446                 vec_add1(mfib_entry_indicies, p->value[0]);
447             }));
448         }
449     }
450
451     vec_sort_with_function(mfib_entry_indicies, mfib_entry_cmp_for_sort);
452
453     vec_foreach(mfib_entry_index, mfib_entry_indicies)
454     {
455         vlib_cli_output(vm, "%U",
456                         format_mfib_entry,
457                         *mfib_entry_index,
458                         MFIB_ENTRY_FORMAT_BRIEF);
459     }
460
461     vec_free(mfib_entry_indicies);
462 }
463
464 static void
465 ip4_mfib_table_show_one (ip4_mfib_t *mfib,
466                          vlib_main_t * vm,
467                          ip4_address_t *src,
468                          ip4_address_t *grp,
469                          u32 mask_len)
470 {
471     vlib_cli_output(vm, "%U",
472                     format_mfib_entry,
473                     ip4_mfib_table_lookup(mfib, src, grp, mask_len),
474                     MFIB_ENTRY_FORMAT_DETAIL);
475 }
476
477 static clib_error_t *
478 ip4_show_mfib (vlib_main_t * vm,
479                unformat_input_t * input,
480                vlib_cli_command_t * cmd)
481 {
482     ip4_main_t * im4 = &ip4_main;
483     mfib_table_t *mfib_table;
484     int verbose, matching, memory;
485     ip4_address_t grp, src = {{0}};
486     u32 mask = 32;
487     u64 total_hash_memory;
488     int i, table_id = -1, fib_index = ~0;
489
490     verbose = 1;
491     memory = matching = 0;
492     total_hash_memory = 0;
493
494     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
495     {
496         if (unformat (input, "brief") || unformat (input, "summary")
497             || unformat (input, "sum"))
498             verbose = 0;
499         else if (unformat (input, "mem") || unformat (input, "memory"))
500             memory = 1;
501         else if (unformat (input, "%U %U",
502                            unformat_ip4_address, &src,
503                            unformat_ip4_address, &grp))
504         {
505             matching = 1;
506             mask = 64;
507         }
508         else if (unformat (input, "%U/%d", unformat_ip4_address, &grp, &mask))
509         {
510             clib_memset(&src, 0, sizeof(src));
511             matching = 1;
512         }
513         else if (unformat (input, "%U", unformat_ip4_address, &grp))
514         {
515             clib_memset(&src, 0, sizeof(src));
516             matching = 1;
517             mask = 32;
518         }
519         else if (unformat (input, "table %d", &table_id))
520             ;
521         else if (unformat (input, "index %d", &fib_index))
522             ;
523         else
524             break;
525     }
526
527     pool_foreach (mfib_table, im4->mfibs)
528      {
529         ip4_mfib_t *mfib = &mfib_table->v4;
530
531         if (table_id >= 0 && table_id != (int)mfib->table_id)
532             continue;
533         if (fib_index != ~0 && fib_index != (int)mfib->index)
534             continue;
535
536         if (memory)
537         {
538             uword hash_size;
539
540             hash_size = 0;
541
542             for (i = 0; i < ARRAY_LEN (mfib->fib_entry_by_dst_address); i++)
543             {
544                 uword * hash = mfib->fib_entry_by_dst_address[i];
545                 if (NULL != hash)
546                 {
547                     hash_size += hash_bytes(hash);
548                 }
549             }
550             if (verbose)
551                 vlib_cli_output (vm, "%U hash:%d",
552                                  format_mfib_table_name, mfib->index,
553                                  FIB_PROTOCOL_IP4,
554                                  hash_size);
555             total_hash_memory += hash_size;
556             continue;
557         }
558
559         vlib_cli_output (vm, "%U, fib_index:%d flags:%U",
560                          format_mfib_table_name, mfib->index, FIB_PROTOCOL_IP4,
561                          mfib->index,
562                          format_mfib_table_flags, mfib_table->mft_flags);
563
564         /* Show summary? */
565         if (! verbose)
566         {
567             vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count");
568             for (i = 0; i < ARRAY_LEN (mfib->fib_entry_by_dst_address); i++)
569             {
570                 uword * hash = mfib->fib_entry_by_dst_address[i];
571                 uword n_elts = hash_elts (hash);
572                 if (n_elts > 0)
573                     vlib_cli_output (vm, "%20d%16d", i, n_elts);
574             }
575             continue;
576         }
577
578         if (!matching)
579         {
580             ip4_mfib_table_show_all(mfib, vm);
581         }
582         else
583         {
584             ip4_mfib_table_show_one(mfib, vm, &src, &grp, mask);
585         }
586     }
587     if (memory)
588         vlib_cli_output (vm, "totals: hash:%ld", total_hash_memory);
589
590     return 0;
591 }
592
593 /* clang-format off */
594 /*?
595  * This command displays the IPv4 MulticasrFIB Tables (VRF Tables) and
596  * the route entries for each table.
597  *
598  * @note This command will run for a long time when the FIB tables are
599  * comprised of millions of entries. For those scenarios, consider displaying
600  * a single table or summary mode.
601  *
602  * @cliexpar
603  * Example of how to display all the IPv4 Multicast FIB tables:
604  * @cliexstart{show ip fib}
605  * ipv4-VRF:0, fib_index 0
606  * (*, 0.0.0.0/0):  flags:D,
607  *  Interfaces:
608  *  multicast-ip4-chain
609  *   [@1]: dpo-drop ip4
610  * (*, 232.1.1.1/32):
611  * Interfaces:
612  *  test-eth1: Forward,
613  *  test-eth2: Forward,
614  *  test-eth0: Accept,
615  * multicast-ip4-chain
616  * [@2]: dpo-replicate: [index:1 buckets:2 to:[0:0]]
617  *   [0] [@1]: ipv4-mcast: test-eth1: IP4: d0:d1:d2:d3:d4:01 -> 01:00:05:00:00:00
618  *   [1] [@1]: ipv4-mcast: test-eth2: IP4: d0:d1:d2:d3:d4:02 -> 01:00:05:00:00:00
619  *
620  * @cliexend
621  * Example of how to display a summary of all IPv4 FIB tables:
622  * @cliexstart{show ip fib summary}
623  * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
624  *     Prefix length         Count
625  *                    0               1
626  *                    8               2
627  *                   32               4
628  * ipv4-VRF:7, fib_index 1, flow hash: src dst sport dport proto
629  *     Prefix length         Count
630  *                    0               1
631  *                    8               2
632  *                   24               2
633  *                   32               4
634  * @cliexend
635  ?*/
636 /* clang-format on */
637 VLIB_CLI_COMMAND (ip4_show_mfib_command, static) = {
638     .path = "show ip mfib",
639     .short_help = "show ip mfib [summary] [table <table-id>] [index <fib-id>] [<grp-addr>[/<mask>]] [<grp-addr>] [<src-addr> <grp-addr>]",
640     .function = ip4_show_mfib,
641 };