MPLS Mcast
[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 ip4_specials[] = {
22     {
23         /* (*,*)/0 */
24         .fp_src_addr = {
25             .ip4.data_u32 = 0,
26         },
27         .fp_grp_addr = {
28             .ip4.data_u32 = 0,
29         },
30         .fp_len  = 0,
31         .fp_proto = FIB_PROTOCOL_IP4,
32     },
33 };
34
35 static u32
36 ip4_create_mfib_with_table_id (u32 table_id)
37 {
38     mfib_table_t *mfib_table;
39
40     pool_get_aligned(ip4_main.mfibs, mfib_table, CLIB_CACHE_LINE_BYTES);
41     memset(mfib_table, 0, sizeof(*mfib_table));
42
43     mfib_table->mft_proto = FIB_PROTOCOL_IP4;
44     mfib_table->mft_index =
45         mfib_table->v4.index =
46             (mfib_table - ip4_main.mfibs);
47
48     hash_set (ip4_main.mfib_index_by_table_id,
49               table_id,
50               mfib_table->mft_index);
51
52     mfib_table->mft_table_id =
53         mfib_table->v4.table_id =
54             table_id;
55
56     mfib_table_lock(mfib_table->mft_index, FIB_PROTOCOL_IP4);
57
58     /*
59      * add the special entries into the new FIB
60      */
61     int ii;
62
63     for (ii = 0; ii < ARRAY_LEN(ip4_specials); ii++)
64     {
65         mfib_prefix_t prefix = ip4_specials[ii];
66
67         prefix.fp_src_addr.ip4.data_u32 =
68             clib_host_to_net_u32(prefix.fp_src_addr.ip4.data_u32);
69         prefix.fp_grp_addr.ip4.data_u32 =
70             clib_host_to_net_u32(prefix.fp_grp_addr.ip4.data_u32);
71
72         mfib_table_entry_update(mfib_table->mft_index,
73                                 &prefix,
74                                 MFIB_SOURCE_DEFAULT_ROUTE,
75                                 MFIB_RPF_ID_NONE,
76                                 MFIB_ENTRY_FLAG_DROP);
77     }
78
79     return (mfib_table->mft_index);
80 }
81
82 void
83 ip4_mfib_table_destroy (ip4_mfib_t *mfib)
84 {
85     mfib_table_t *mfib_table = (mfib_table_t*)mfib;
86     int ii;
87
88     /*
89      * remove all the specials we added when the table was created.
90      */
91     for (ii = 0; ii < ARRAY_LEN(ip4_specials); ii++)
92     {
93         fib_node_index_t mfei;
94         mfib_prefix_t prefix = ip4_specials[ii];
95
96         prefix.fp_src_addr.ip4.data_u32 =
97             clib_host_to_net_u32(prefix.fp_src_addr.ip4.data_u32);
98         prefix.fp_grp_addr.ip4.data_u32 =
99             clib_host_to_net_u32(prefix.fp_grp_addr.ip4.data_u32);
100
101         mfei = mfib_table_lookup(mfib_table->mft_index, &prefix);
102         mfib_table_entry_delete_index(mfei, MFIB_SOURCE_DEFAULT_ROUTE);
103     }
104
105     /*
106      * validate no more routes.
107      */
108     ASSERT(0 == mfib_table->mft_total_route_counts);
109     ASSERT(~0 != mfib_table->mft_table_id);
110
111     hash_unset (ip4_main.mfib_index_by_table_id, mfib_table->mft_table_id);
112     pool_put(ip4_main.mfibs, mfib_table);
113 }
114
115 u32
116 ip4_mfib_table_find_or_create_and_lock (u32 table_id)
117 {
118     u32 index;
119
120     index = ip4_mfib_index_from_table_id(table_id);
121     if (~0 == index)
122         return ip4_create_mfib_with_table_id(table_id);
123     mfib_table_lock(index, FIB_PROTOCOL_IP4);
124
125     return (index);
126 }
127
128 u32
129 ip4_mfib_table_get_index_for_sw_if_index (u32 sw_if_index)
130 {
131     if (sw_if_index >= vec_len(ip4_main.mfib_index_by_sw_if_index))
132     {
133         /*
134          * This is the case for interfaces that are not yet mapped to
135          * a IP table
136          */
137         return (~0);
138     }
139     return (ip4_main.mfib_index_by_sw_if_index[sw_if_index]);
140 }
141
142 #define IPV4_MFIB_GRP_LEN(_len)\
143     (_len > 32 ? 32 : _len)
144
145 #define IP4_MFIB_MK_KEY(_grp, _src, _len, _key)                         \
146 {                                                                       \
147     _key  = ((u64)(_grp->data_u32 &                                     \
148                    ip4_main.fib_masks[IPV4_MFIB_GRP_LEN(_len)])) << 32; \
149     _key |= _src->data_u32;                                             \
150 }
151 #define IP4_MFIB_MK_GRP_KEY(_grp, _len, _key)                           \
152 {                                                                       \
153     _key  = ((u64)(_grp->data_u32 &                                     \
154                    ip4_main.fib_masks[IPV4_MFIB_GRP_LEN(_len)])) << 32; \
155 }
156
157 /*
158  * ip4_fib_table_lookup_exact_match
159  *
160  * Exact match prefix lookup
161  */
162 fib_node_index_t
163 ip4_mfib_table_lookup_exact_match (const ip4_mfib_t *mfib,
164                                    const ip4_address_t *grp,
165                                    const ip4_address_t *src,
166                                    u32 len)
167 {
168     uword * hash, * result;
169     u64 key;
170
171     hash = mfib->fib_entry_by_dst_address[len];
172     IP4_MFIB_MK_KEY(grp, src, len, key);
173
174     result = hash_get(hash, key);
175
176     if (NULL != result) {
177         return (result[0]);
178     }
179     return (FIB_NODE_INDEX_INVALID);
180 }
181
182 /*
183  * ip4_fib_table_lookup
184  *
185  * Longest prefix match
186  */
187 fib_node_index_t
188 ip4_mfib_table_lookup (const ip4_mfib_t *mfib,
189                        const ip4_address_t *src,
190                        const ip4_address_t *grp,
191                        u32 len)
192 {
193     uword * hash, * result;
194     i32 mask_len;
195     u64 key;
196
197     mask_len = len;
198
199     if (PREDICT_TRUE(64 == mask_len))
200     {
201         hash = mfib->fib_entry_by_dst_address[mask_len];
202         IP4_MFIB_MK_KEY(grp, src, mask_len, key);
203
204         result = hash_get (hash, key);
205
206         if (NULL != result) {
207             return (result[0]);
208         }
209     }
210
211     for (mask_len = 32; mask_len >= 0; mask_len--)
212     {
213         hash = mfib->fib_entry_by_dst_address[mask_len];
214         IP4_MFIB_MK_GRP_KEY(grp, mask_len, key);
215
216         result = hash_get (hash, key);
217
218         if (NULL != result) {
219             return (result[0]);
220         }
221     }
222     return (FIB_NODE_INDEX_INVALID);
223 }
224
225 void
226 ip4_mfib_table_entry_insert (ip4_mfib_t *mfib,
227                              const ip4_address_t *grp,
228                              const ip4_address_t *src,
229                              u32 len,
230                              fib_node_index_t fib_entry_index)
231 {
232     uword * hash, * result;
233     u64 key;
234
235     IP4_MFIB_MK_KEY(grp, src, len, key);
236     hash = mfib->fib_entry_by_dst_address[len];
237     result = hash_get (hash, key);
238
239     if (NULL == result) {
240         /*
241          * adding a new entry
242          */
243         if (NULL == hash) {
244             hash = hash_create (32 /* elts */, sizeof (uword));
245             hash_set_flags (hash, HASH_FLAG_NO_AUTO_SHRINK);
246         }
247         hash = hash_set(hash, key, fib_entry_index);
248         mfib->fib_entry_by_dst_address[len] = hash;
249     }
250     else
251     {
252         ASSERT(0);
253     }
254 }
255
256 void
257 ip4_mfib_table_entry_remove (ip4_mfib_t *mfib,
258                              const ip4_address_t *grp,
259                              const ip4_address_t *src,
260                              u32 len)
261 {
262     uword * hash, * result;
263     u64 key;
264
265     IP4_MFIB_MK_KEY(grp, src, len, key);
266     hash = mfib->fib_entry_by_dst_address[len];
267     result = hash_get (hash, key);
268
269     if (NULL == result)
270     {
271         /*
272          * removing a non-existant entry. i'll allow it.
273          */
274     }
275     else
276     {
277         hash_unset(hash, key);
278     }
279
280     mfib->fib_entry_by_dst_address[len] = hash;
281 }
282
283 void
284 ip4_mfib_table_walk (ip4_mfib_t *mfib,
285                      mfib_table_walk_fn_t fn,
286                      void *ctx)
287 {
288     int i;
289
290     for (i = 0; i < ARRAY_LEN (mfib->fib_entry_by_dst_address); i++)
291     {
292         uword * hash = mfib->fib_entry_by_dst_address[i];
293
294         if (NULL != hash)
295         {
296             hash_pair_t * p;
297
298             hash_foreach_pair (p, hash,
299             ({
300                 fn(p->value[0], ctx);
301             }));
302         }
303     }
304 }
305
306 static void
307 ip4_mfib_table_show_all (ip4_mfib_t *mfib,
308                          vlib_main_t * vm)
309 {
310     fib_node_index_t *mfib_entry_indicies;
311     fib_node_index_t *mfib_entry_index;
312     int i;
313
314     mfib_entry_indicies = NULL;
315
316     for (i = 0; i < ARRAY_LEN (mfib->fib_entry_by_dst_address); i++)
317     {
318         uword * hash = mfib->fib_entry_by_dst_address[i];
319
320         if (NULL != hash)
321         {
322             hash_pair_t * p;
323
324             hash_foreach_pair (p, hash,
325             ({
326                 vec_add1(mfib_entry_indicies, p->value[0]);
327             }));
328         }
329     }
330
331     vec_sort_with_function(mfib_entry_indicies, mfib_entry_cmp_for_sort);
332
333     vec_foreach(mfib_entry_index, mfib_entry_indicies)
334     {
335         vlib_cli_output(vm, "%U",
336                         format_mfib_entry,
337                         *mfib_entry_index,
338                         MFIB_ENTRY_FORMAT_BRIEF);
339     }
340
341     vec_free(mfib_entry_indicies);
342 }
343
344 static void
345 ip4_mfib_table_show_one (ip4_mfib_t *mfib,
346                          vlib_main_t * vm,
347                          ip4_address_t *src,
348                          ip4_address_t *grp,
349                          u32 mask_len)
350 {
351     vlib_cli_output(vm, "%U",
352                     format_mfib_entry,
353                     ip4_mfib_table_lookup(mfib, src, grp, mask_len),
354                     MFIB_ENTRY_FORMAT_DETAIL);
355 }
356
357 static clib_error_t *
358 ip4_show_mfib (vlib_main_t * vm,
359                unformat_input_t * input,
360                vlib_cli_command_t * cmd)
361 {
362     ip4_main_t * im4 = &ip4_main;
363     mfib_table_t *mfib_table;
364     int verbose, matching;
365     ip4_address_t grp, src = {{0}};
366     u32 mask = 32;
367     int i, table_id = -1, fib_index = ~0;
368
369     verbose = 1;
370     matching = 0;
371
372     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
373     {
374         if (unformat (input, "brief") || unformat (input, "summary")
375             || unformat (input, "sum"))
376             verbose = 0;
377
378         else if (unformat (input, "%U %U",
379                            unformat_ip4_address, &src,
380                            unformat_ip4_address, &grp))
381         {
382             matching = 1;
383             mask = 64;
384         }
385         else if (unformat (input, "%U", unformat_ip4_address, &grp))
386         {
387             matching = 1;
388             mask = 32;
389         }
390         else if (unformat (input, "%U/%d",
391                            unformat_ip4_address, &grp, &mask))
392             matching = 1;
393         else if (unformat (input, "table %d", &table_id))
394             ;
395         else if (unformat (input, "index %d", &fib_index))
396             ;
397         else
398             break;
399     }
400
401     pool_foreach (mfib_table, im4->mfibs,
402     ({
403         ip4_mfib_t *mfib = &mfib_table->v4;
404
405         if (table_id >= 0 && table_id != (int)mfib->table_id)
406             continue;
407         if (fib_index != ~0 && fib_index != (int)mfib->index)
408             continue;
409
410         vlib_cli_output (vm, "%U, fib_index %d",
411                          format_mfib_table_name, mfib->index, FIB_PROTOCOL_IP4,
412                          mfib->index);
413
414         /* Show summary? */
415         if (! verbose)
416         {
417             vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count");
418             for (i = 0; i < ARRAY_LEN (mfib->fib_entry_by_dst_address); i++)
419             {
420                 uword * hash = mfib->fib_entry_by_dst_address[i];
421                 uword n_elts = hash_elts (hash);
422                 if (n_elts > 0)
423                     vlib_cli_output (vm, "%20d%16d", i, n_elts);
424             }
425             continue;
426         }
427
428         if (!matching)
429         {
430             ip4_mfib_table_show_all(mfib, vm);
431         }
432         else
433         {
434             ip4_mfib_table_show_one(mfib, vm, &src, &grp, mask);
435         }
436     }));
437
438     return 0;
439 }
440
441 /*?
442  * This command displays the IPv4 MulticasrFIB Tables (VRF Tables) and
443  * the route entries for each table.
444  *
445  * @note This command will run for a long time when the FIB tables are
446  * comprised of millions of entries. For those senarios, consider displaying
447  * a single table or summary mode.
448  *
449  * @cliexpar
450  * Example of how to display all the IPv4 Multicast FIB tables:
451  * @cliexstart{show ip fib}
452  * ipv4-VRF:0, fib_index 0
453  * (*, 0.0.0.0/0):  flags:D,
454  *  Interfaces:
455  *  multicast-ip4-chain
456  *   [@1]: dpo-drop ip4
457  * (*, 232.1.1.1/32):
458  * Interfaces:
459  *  test-eth1: Forward,
460  *  test-eth2: Forward,
461  *  test-eth0: Accept,
462  * multicast-ip4-chain
463  * [@2]: dpo-replicate: [index:1 buckets:2 to:[0:0]]
464  *   [0] [@1]: ipv4-mcast: test-eth1: IP4: d0:d1:d2:d3:d4:01 -> 01:00:05:00:00:00
465  *   [1] [@1]: ipv4-mcast: test-eth2: IP4: d0:d1:d2:d3:d4:02 -> 01:00:05:00:00:00
466  *
467  * @cliexend
468  * Example of how to display a summary of all IPv4 FIB tables:
469  * @cliexstart{show ip fib summary}
470  * ipv4-VRF:0, fib_index 0, flow hash: src dst sport dport proto
471  *     Prefix length         Count
472  *                    0               1
473  *                    8               2
474  *                   32               4
475  * ipv4-VRF:7, fib_index 1, flow hash: src dst sport dport proto
476  *     Prefix length         Count
477  *                    0               1
478  *                    8               2
479  *                   24               2
480  *                   32               4
481  * @cliexend
482  ?*/
483 /* *INDENT-OFF* */
484 VLIB_CLI_COMMAND (ip4_show_mfib_command, static) = {
485     .path = "show ip mfib",
486     .short_help = "show ip mfib [summary] [table <table-id>] [index <fib-id>] [<grp-addr>[/<mask>]] [<grp-addr>] [<src-addr> <grp-addr>]",
487     .function = ip4_show_mfib,
488 };
489 /* *INDENT-ON* */