Cache a 'has-features' flag on the adjacency for faster access. Reclaim the node_inde...
[vpp.git] / src / vnet / ip / lookup.c
1 /*
2  * Copyright (c) 2015 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  * ip/ip_lookup.c: ip4/6 adjacency and lookup table managment
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #include <vnet/ip/ip.h>
41 #include <vnet/adj/adj.h>
42 #include <vnet/fib/fib_table.h>
43 #include <vnet/fib/ip4_fib.h>
44 #include <vnet/fib/ip6_fib.h>
45 #include <vnet/mpls/mpls.h>
46 #include <vnet/mfib/mfib_table.h>
47 #include <vnet/dpo/drop_dpo.h>
48 #include <vnet/dpo/classify_dpo.h>
49 #include <vnet/dpo/punt_dpo.h>
50 #include <vnet/dpo/receive_dpo.h>
51 #include <vnet/dpo/ip_null_dpo.h>
52 #include <vnet/ip/ip6_neighbor.h>
53
54 /**
55  * @file
56  * @brief IPv4 and IPv6 adjacency and lookup table managment.
57  *
58  */
59
60 clib_error_t *
61 ip_interface_address_add_del (ip_lookup_main_t * lm,
62                               u32 sw_if_index,
63                               void *addr_fib,
64                               u32 address_length,
65                               u32 is_del, u32 * result_if_address_index)
66 {
67   vnet_main_t *vnm = vnet_get_main ();
68   ip_interface_address_t *a, *prev, *next;
69   uword *p = mhash_get (&lm->address_to_if_address_index, addr_fib);
70
71   vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index,
72                            sw_if_index, ~0);
73   a = p ? pool_elt_at_index (lm->if_address_pool, p[0]) : 0;
74
75   /* Verify given length. */
76   if ((a && (address_length != a->address_length)) || (address_length == 0))
77     {
78       vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
79       return clib_error_create
80         ("%U wrong length (expected %d) for interface %U",
81          lm->format_address_and_length, addr_fib,
82          address_length, a ? a->address_length : -1,
83          format_vnet_sw_if_index_name, vnm, sw_if_index);
84     }
85
86   if (is_del)
87     {
88       if (!a)
89         {
90           vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
91           vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
92           return clib_error_create ("%U not found for interface %U",
93                                     lm->format_address_and_length,
94                                     addr_fib, address_length,
95                                     format_vnet_sw_interface_name, vnm, si);
96         }
97
98       if (a->prev_this_sw_interface != ~0)
99         {
100           prev =
101             pool_elt_at_index (lm->if_address_pool,
102                                a->prev_this_sw_interface);
103           prev->next_this_sw_interface = a->next_this_sw_interface;
104         }
105       if (a->next_this_sw_interface != ~0)
106         {
107           next =
108             pool_elt_at_index (lm->if_address_pool,
109                                a->next_this_sw_interface);
110           next->prev_this_sw_interface = a->prev_this_sw_interface;
111
112           if (a->prev_this_sw_interface == ~0)
113             lm->if_address_pool_index_by_sw_if_index[sw_if_index] =
114               a->next_this_sw_interface;
115         }
116
117       if ((a->next_this_sw_interface == ~0)
118           && (a->prev_this_sw_interface == ~0))
119         lm->if_address_pool_index_by_sw_if_index[sw_if_index] = ~0;
120
121       mhash_unset (&lm->address_to_if_address_index, addr_fib,
122                    /* old_value */ 0);
123       pool_put (lm->if_address_pool, a);
124
125       if (result_if_address_index)
126         *result_if_address_index = ~0;
127     }
128
129   else if (!a)
130     {
131       u32 pi;                   /* previous index */
132       u32 ai;
133       u32 hi;                   /* head index */
134
135       pool_get (lm->if_address_pool, a);
136       memset (a, ~0, sizeof (a[0]));
137       ai = a - lm->if_address_pool;
138
139       hi = pi = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
140       prev = 0;
141       while (pi != (u32) ~ 0)
142         {
143           prev = pool_elt_at_index (lm->if_address_pool, pi);
144           pi = prev->next_this_sw_interface;
145         }
146       pi = prev ? prev - lm->if_address_pool : (u32) ~ 0;
147
148       a->address_key = mhash_set (&lm->address_to_if_address_index,
149                                   addr_fib, ai, /* old_value */ 0);
150       a->address_length = address_length;
151       a->sw_if_index = sw_if_index;
152       a->flags = 0;
153       a->prev_this_sw_interface = pi;
154       a->next_this_sw_interface = ~0;
155       if (prev)
156         prev->next_this_sw_interface = ai;
157
158       lm->if_address_pool_index_by_sw_if_index[sw_if_index] =
159         (hi != ~0) ? hi : ai;
160       if (result_if_address_index)
161         *result_if_address_index = ai;
162     }
163   else
164     {
165       if (result_if_address_index)
166         *result_if_address_index = a - lm->if_address_pool;
167     }
168
169
170   return /* no error */ 0;
171 }
172
173 static clib_error_t *
174 ip_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
175 {
176   vec_validate_init_empty (ip4_main.
177                            lookup_main.if_address_pool_index_by_sw_if_index,
178                            sw_if_index, ~0);
179   vec_validate_init_empty (ip6_main.
180                            lookup_main.if_address_pool_index_by_sw_if_index,
181                            sw_if_index, ~0);
182
183   return (NULL);
184 }
185
186 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip_sw_interface_add_del);
187
188 void
189 ip_lookup_init (ip_lookup_main_t * lm, u32 is_ip6)
190 {
191   /* ensure that adjacency is cacheline aligned and sized */
192   STATIC_ASSERT (STRUCT_OFFSET_OF (ip_adjacency_t, cacheline0) == 0,
193                  "Cache line marker must be 1st element in struct");
194   STATIC_ASSERT (STRUCT_OFFSET_OF (ip_adjacency_t, cacheline1) ==
195                  CLIB_CACHE_LINE_BYTES,
196                  "Data in cache line 0 is bigger than cache line size");
197
198   /* Preallocate three "special" adjacencies */
199   lm->adjacency_heap = adj_pool;
200
201   if (!lm->fib_result_n_bytes)
202     lm->fib_result_n_bytes = sizeof (uword);
203
204   lm->is_ip6 = is_ip6;
205   if (is_ip6)
206     {
207       lm->format_address_and_length = format_ip6_address_and_length;
208       mhash_init (&lm->address_to_if_address_index, sizeof (uword),
209                   sizeof (ip6_address_fib_t));
210     }
211   else
212     {
213       lm->format_address_and_length = format_ip4_address_and_length;
214       mhash_init (&lm->address_to_if_address_index, sizeof (uword),
215                   sizeof (ip4_address_fib_t));
216     }
217
218   {
219     int i;
220
221     /* Setup all IP protocols to be punted and builtin-unknown. */
222     for (i = 0; i < 256; i++)
223       {
224         lm->local_next_by_ip_protocol[i] = IP_LOCAL_NEXT_PUNT;
225         lm->builtin_protocol_by_ip_protocol[i] = IP_BUILTIN_PROTOCOL_UNKNOWN;
226       }
227
228     lm->local_next_by_ip_protocol[IP_PROTOCOL_UDP] = IP_LOCAL_NEXT_UDP_LOOKUP;
229     lm->local_next_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 :
230                                   IP_PROTOCOL_ICMP] = IP_LOCAL_NEXT_ICMP;
231     lm->builtin_protocol_by_ip_protocol[IP_PROTOCOL_UDP] =
232       IP_BUILTIN_PROTOCOL_UDP;
233     lm->builtin_protocol_by_ip_protocol[is_ip6 ? IP_PROTOCOL_ICMP6 :
234                                         IP_PROTOCOL_ICMP] =
235       IP_BUILTIN_PROTOCOL_ICMP;
236   }
237 }
238
239 u8 *
240 format_ip_flow_hash_config (u8 * s, va_list * args)
241 {
242   flow_hash_config_t flow_hash_config = va_arg (*args, u32);
243
244 #define _(n,v) if (flow_hash_config & v) s = format (s, "%s ", #n);
245   foreach_flow_hash_bit;
246 #undef _
247
248   return s;
249 }
250
251 u8 *
252 format_ip_lookup_next (u8 * s, va_list * args)
253 {
254   ip_lookup_next_t n = va_arg (*args, ip_lookup_next_t);
255   char *t = 0;
256
257   switch (n)
258     {
259     default:
260       s = format (s, "unknown %d", n);
261       return s;
262
263     case IP_LOOKUP_NEXT_DROP:
264       t = "drop";
265       break;
266     case IP_LOOKUP_NEXT_PUNT:
267       t = "punt";
268       break;
269     case IP_LOOKUP_NEXT_ARP:
270       t = "arp";
271       break;
272     case IP_LOOKUP_NEXT_MIDCHAIN:
273       t = "midchain";
274       break;
275     case IP_LOOKUP_NEXT_GLEAN:
276       t = "glean";
277       break;
278     case IP_LOOKUP_NEXT_MCAST:
279       t = "mcast";
280       break;
281     case IP_LOOKUP_NEXT_REWRITE:
282       break;
283     }
284
285   if (t)
286     vec_add (s, t, strlen (t));
287
288   return s;
289 }
290
291 u8 *
292 format_ip_adjacency_packet_data (u8 * s, va_list * args)
293 {
294   u32 adj_index = va_arg (*args, u32);
295   u8 *packet_data = va_arg (*args, u8 *);
296   u32 n_packet_data_bytes = va_arg (*args, u32);
297   ip_adjacency_t *adj = adj_get (adj_index);
298
299   switch (adj->lookup_next_index)
300     {
301     case IP_LOOKUP_NEXT_REWRITE:
302     case IP_LOOKUP_NEXT_MCAST:
303       s =
304         format (s, "%U", format_hex_bytes, packet_data, n_packet_data_bytes);
305       break;
306
307     default:
308       break;
309     }
310
311   return s;
312 }
313
314 static uword
315 unformat_dpo (unformat_input_t * input, va_list * args)
316 {
317   dpo_id_t *dpo = va_arg (*args, dpo_id_t *);
318   fib_protocol_t fp = va_arg (*args, int);
319   dpo_proto_t proto;
320
321   proto = fib_proto_to_dpo (fp);
322
323   if (unformat (input, "drop"))
324     dpo_copy (dpo, drop_dpo_get (proto));
325   else if (unformat (input, "punt"))
326     dpo_copy (dpo, punt_dpo_get (proto));
327   else if (unformat (input, "local"))
328     receive_dpo_add_or_lock (proto, ~0, NULL, dpo);
329   else if (unformat (input, "null-send-unreach"))
330     ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_SEND_ICMP_UNREACH, dpo);
331   else if (unformat (input, "null-send-prohibit"))
332     ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_SEND_ICMP_PROHIBIT, dpo);
333   else if (unformat (input, "null"))
334     ip_null_dpo_add_and_lock (proto, IP_NULL_ACTION_NONE, dpo);
335   else if (unformat (input, "classify"))
336     {
337       u32 classify_table_index;
338
339       if (!unformat (input, "%d", &classify_table_index))
340         {
341           clib_warning ("classify adj must specify table index");
342           return 0;
343         }
344
345       dpo_set (dpo, DPO_CLASSIFY, proto,
346                classify_dpo_create (proto, classify_table_index));
347     }
348   else
349     return 0;
350
351   return 1;
352 }
353
354 const ip46_address_t zero_addr = {
355   .as_u64 = {
356              0, 0},
357 };
358
359 u32
360 fib_table_id_find_fib_index (fib_protocol_t proto, u32 table_id)
361 {
362   ip4_main_t *im4 = &ip4_main;
363   ip6_main_t *im6 = &ip6_main;
364   uword *p;
365
366   switch (proto)
367     {
368     case FIB_PROTOCOL_IP4:
369       p = hash_get (im4->fib_index_by_table_id, table_id);
370       break;
371     case FIB_PROTOCOL_IP6:
372       p = hash_get (im6->fib_index_by_table_id, table_id);
373       break;
374     default:
375       p = NULL;
376       break;
377     }
378   if (NULL != p)
379     {
380       return (p[0]);
381     }
382   return (~0);
383 }
384
385 clib_error_t *
386 vnet_ip_route_cmd (vlib_main_t * vm,
387                    unformat_input_t * main_input, vlib_cli_command_t * cmd)
388 {
389   unformat_input_t _line_input, *line_input = &_line_input;
390   fib_route_path_t *rpaths = NULL, rpath;
391   dpo_id_t dpo = DPO_INVALID, *dpos = NULL;
392   fib_prefix_t *prefixs = NULL, pfx;
393   mpls_label_t out_label, via_label;
394   clib_error_t *error = NULL;
395   u32 table_id, is_del;
396   vnet_main_t *vnm;
397   u32 fib_index;
398   f64 count;
399   int i;
400
401   vnm = vnet_get_main ();
402   is_del = 0;
403   table_id = 0;
404   count = 1;
405   memset (&pfx, 0, sizeof (pfx));
406   out_label = via_label = MPLS_LABEL_INVALID;
407
408   /* Get a line of input. */
409   if (!unformat_user (main_input, unformat_line_input, line_input))
410     return 0;
411
412   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
413     {
414       memset (&rpath, 0, sizeof (rpath));
415
416       if (unformat (line_input, "table %d", &table_id))
417         ;
418       else if (unformat (line_input, "del"))
419         is_del = 1;
420       else if (unformat (line_input, "add"))
421         is_del = 0;
422       else if (unformat (line_input, "resolve-via-host"))
423         {
424           if (vec_len (rpaths) == 0)
425             {
426               error = clib_error_return (0, "Paths then flags");
427               goto done;
428             }
429           rpaths[vec_len (rpaths) - 1].frp_flags |=
430             FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
431         }
432       else if (unformat (line_input, "resolve-via-attached"))
433         {
434           if (vec_len (rpaths) == 0)
435             {
436               error = clib_error_return (0, "Paths then flags");
437               goto done;
438             }
439           rpaths[vec_len (rpaths) - 1].frp_flags |=
440             FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
441         }
442       else if (unformat (line_input, "out-label %U",
443                          unformat_mpls_unicast_label, &out_label))
444         {
445           if (vec_len (rpaths) == 0)
446             {
447               error = clib_error_return (0, "Paths then labels");
448               goto done;
449             }
450           vec_add1 (rpaths[vec_len (rpaths) - 1].frp_label_stack, out_label);
451         }
452       else if (unformat (line_input, "via-label %U",
453                          unformat_mpls_unicast_label, &rpath.frp_local_label))
454         {
455           rpath.frp_weight = 1;
456           rpath.frp_proto = FIB_PROTOCOL_MPLS;
457           rpath.frp_sw_if_index = ~0;
458           vec_add1 (rpaths, rpath);
459         }
460       else if (unformat (line_input, "count %f", &count))
461         ;
462
463       else if (unformat (line_input, "%U/%d",
464                          unformat_ip4_address, &pfx.fp_addr.ip4, &pfx.fp_len))
465         {
466           pfx.fp_proto = FIB_PROTOCOL_IP4;
467           vec_add1 (prefixs, pfx);
468         }
469       else if (unformat (line_input, "%U/%d",
470                          unformat_ip6_address, &pfx.fp_addr.ip6, &pfx.fp_len))
471         {
472           pfx.fp_proto = FIB_PROTOCOL_IP6;
473           vec_add1 (prefixs, pfx);
474         }
475       else if (unformat (line_input, "via %U %U weight %u",
476                          unformat_ip4_address,
477                          &rpath.frp_addr.ip4,
478                          unformat_vnet_sw_interface, vnm,
479                          &rpath.frp_sw_if_index, &rpath.frp_weight))
480         {
481           rpath.frp_proto = FIB_PROTOCOL_IP4;
482           vec_add1 (rpaths, rpath);
483         }
484
485       else if (unformat (line_input, "via %U %U weight %u",
486                          unformat_ip6_address,
487                          &rpath.frp_addr.ip6,
488                          unformat_vnet_sw_interface, vnm,
489                          &rpath.frp_sw_if_index, &rpath.frp_weight))
490         {
491           rpath.frp_proto = FIB_PROTOCOL_IP6;
492           vec_add1 (rpaths, rpath);
493         }
494
495       else if (unformat (line_input, "via %U %U",
496                          unformat_ip4_address,
497                          &rpath.frp_addr.ip4,
498                          unformat_vnet_sw_interface, vnm,
499                          &rpath.frp_sw_if_index))
500         {
501           rpath.frp_weight = 1;
502           rpath.frp_proto = FIB_PROTOCOL_IP4;
503           vec_add1 (rpaths, rpath);
504         }
505
506       else if (unformat (line_input, "via %U %U",
507                          unformat_ip6_address,
508                          &rpath.frp_addr.ip6,
509                          unformat_vnet_sw_interface, vnm,
510                          &rpath.frp_sw_if_index))
511         {
512           rpath.frp_weight = 1;
513           rpath.frp_proto = FIB_PROTOCOL_IP6;
514           vec_add1 (rpaths, rpath);
515         }
516       else if (unformat (line_input, "via %U next-hop-table %d",
517                          unformat_ip4_address,
518                          &rpath.frp_addr.ip4, &rpath.frp_fib_index))
519         {
520           rpath.frp_weight = 1;
521           rpath.frp_sw_if_index = ~0;
522           rpath.frp_proto = FIB_PROTOCOL_IP4;
523           vec_add1 (rpaths, rpath);
524         }
525       else if (unformat (line_input, "via %U next-hop-table %d",
526                          unformat_ip6_address,
527                          &rpath.frp_addr.ip6, &rpath.frp_fib_index))
528         {
529           rpath.frp_weight = 1;
530           rpath.frp_sw_if_index = ~0;
531           rpath.frp_proto = FIB_PROTOCOL_IP6;
532           vec_add1 (rpaths, rpath);
533         }
534       else if (unformat (line_input, "via %U",
535                          unformat_ip4_address, &rpath.frp_addr.ip4))
536         {
537           /*
538            * the recursive next-hops are by default in the same table
539            * as the prefix
540            */
541           rpath.frp_fib_index = table_id;
542           rpath.frp_weight = 1;
543           rpath.frp_sw_if_index = ~0;
544           rpath.frp_proto = FIB_PROTOCOL_IP4;
545           vec_add1 (rpaths, rpath);
546         }
547       else if (unformat (line_input, "via %U",
548                          unformat_ip6_address, &rpath.frp_addr.ip6))
549         {
550           rpath.frp_fib_index = table_id;
551           rpath.frp_weight = 1;
552           rpath.frp_sw_if_index = ~0;
553           rpath.frp_proto = FIB_PROTOCOL_IP6;
554           vec_add1 (rpaths, rpath);
555         }
556       else if (unformat (line_input,
557                          "lookup in table %d", &rpath.frp_fib_index))
558         {
559           rpath.frp_proto = pfx.fp_proto;
560           rpath.frp_sw_if_index = ~0;
561           vec_add1 (rpaths, rpath);
562         }
563       else if (vec_len (prefixs) > 0 &&
564                unformat (line_input, "via %U",
565                          unformat_vnet_sw_interface, vnm,
566                          &rpath.frp_sw_if_index))
567         {
568           rpath.frp_weight = 1;
569           rpath.frp_proto = prefixs[0].fp_proto;
570           vec_add1 (rpaths, rpath);
571         }
572       else if (vec_len (prefixs) > 0 &&
573                unformat (line_input, "via %U",
574                          unformat_dpo, &dpo, prefixs[0].fp_proto))
575         {
576           vec_add1 (dpos, dpo);
577         }
578       else
579         {
580           error = unformat_parse_error (line_input);
581           goto done;
582         }
583     }
584
585   if (vec_len (prefixs) == 0)
586     {
587       error =
588         clib_error_return (0, "expected ip4/ip6 destination address/length.");
589       goto done;
590     }
591
592   if (!is_del && vec_len (rpaths) + vec_len (dpos) == 0)
593     {
594       error = clib_error_return (0, "expected paths.");
595       goto done;
596     }
597
598   if (~0 == table_id)
599     {
600       /*
601        * if no table_id is passed we will manipulate the default
602        */
603       fib_index = 0;
604     }
605   else
606     {
607       fib_index = fib_table_id_find_fib_index (prefixs[0].fp_proto, table_id);
608
609       if (~0 == fib_index)
610         {
611           error = clib_error_return (0, "Nonexistent table id %d", table_id);
612           goto done;
613         }
614     }
615
616   for (i = 0; i < vec_len (prefixs); i++)
617     {
618       if (is_del && 0 == vec_len (rpaths))
619         {
620           fib_table_entry_delete (fib_index, &prefixs[i], FIB_SOURCE_CLI);
621         }
622       else if (!is_del && 1 == vec_len (dpos))
623         {
624           fib_table_entry_special_dpo_add (fib_index,
625                                            &prefixs[i],
626                                            FIB_SOURCE_CLI,
627                                            FIB_ENTRY_FLAG_EXCLUSIVE,
628                                            &dpos[0]);
629           dpo_reset (&dpos[0]);
630         }
631       else if (vec_len (dpos) > 0)
632         {
633           error =
634             clib_error_return (0,
635                                "Load-balancing over multiple special adjacencies is unsupported");
636           goto done;
637         }
638       else if (0 < vec_len (rpaths))
639         {
640           u32 k, j, n, incr;
641           ip46_address_t dst = prefixs[i].fp_addr;
642           f64 t[2];
643           n = count;
644           t[0] = vlib_time_now (vm);
645           incr = 1 << ((FIB_PROTOCOL_IP4 == prefixs[0].fp_proto ? 32 : 128) -
646                        prefixs[i].fp_len);
647
648           for (k = 0; k < n; k++)
649             {
650               for (j = 0; j < vec_len (rpaths); j++)
651                 {
652                   u32 fi;
653                   /*
654                    * the CLI parsing stored table Ids, swap to FIB indicies
655                    */
656                   fi = fib_table_id_find_fib_index (prefixs[i].fp_proto,
657                                                     rpaths[i].frp_fib_index);
658
659                   if (~0 == fi)
660                     {
661                       error =
662                         clib_error_return (0, "Via table %d does not exist",
663                                            rpaths[i].frp_fib_index);
664                       goto done;
665                     }
666                   rpaths[i].frp_fib_index = fi;
667
668                   fib_prefix_t rpfx = {
669                     .fp_len = prefixs[i].fp_len,
670                     .fp_proto = prefixs[i].fp_proto,
671                     .fp_addr = dst,
672                   };
673
674                   if (is_del)
675                     fib_table_entry_path_remove2 (fib_index,
676                                                   &rpfx,
677                                                   FIB_SOURCE_CLI, &rpaths[j]);
678                   else
679                     fib_table_entry_path_add2 (fib_index,
680                                                &rpfx,
681                                                FIB_SOURCE_CLI,
682                                                FIB_ENTRY_FLAG_NONE,
683                                                &rpaths[j]);
684                 }
685
686               if (FIB_PROTOCOL_IP4 == prefixs[0].fp_proto)
687                 {
688                   dst.ip4.as_u32 =
689                     clib_host_to_net_u32 (incr +
690                                           clib_net_to_host_u32 (dst.
691                                                                 ip4.as_u32));
692                 }
693               else
694                 {
695                   int bucket = (incr < 64 ? 0 : 1);
696                   dst.ip6.as_u64[bucket] =
697                     clib_host_to_net_u64 (incr +
698                                           clib_net_to_host_u64 (dst.ip6.as_u64
699                                                                 [bucket]));
700
701                 }
702             }
703           t[1] = vlib_time_now (vm);
704           if (count > 1)
705             vlib_cli_output (vm, "%.6e routes/sec", count / (t[1] - t[0]));
706         }
707       else
708         {
709           error = clib_error_return (0, "Don't understand what you want...");
710           goto done;
711         }
712     }
713
714
715 done:
716   vec_free (dpos);
717   vec_free (prefixs);
718   vec_free (rpaths);
719   unformat_free (line_input);
720   return error;
721 }
722
723 /* *INDENT-OFF* */
724 VLIB_CLI_COMMAND (vlib_cli_ip_command, static) = {
725   .path = "ip",
726   .short_help = "Internet protocol (IP) commands",
727 };
728 /* *INDENT-ON* */
729
730 /* *INDENT-OFF* */
731 VLIB_CLI_COMMAND (vlib_cli_ip6_command, static) = {
732   .path = "ip6",
733   .short_help = "Internet protocol version 6 (IPv6) commands",
734 };
735 /* *INDENT-ON* */
736
737 /* *INDENT-OFF* */
738 VLIB_CLI_COMMAND (vlib_cli_show_ip_command, static) = {
739   .path = "show ip",
740   .short_help = "Internet protocol (IP) show commands",
741 };
742 /* *INDENT-ON* */
743
744 /* *INDENT-OFF* */
745 VLIB_CLI_COMMAND (vlib_cli_show_ip6_command, static) = {
746   .path = "show ip6",
747   .short_help = "Internet protocol version 6 (IPv6) show commands",
748 };
749 /* *INDENT-ON* */
750
751 /*?
752  * This command is used to add or delete IPv4 or IPv6 routes. All
753  * IP Addresses ('<em><dst-ip-addr>/<width></em>',
754  * '<em><next-hop-ip-addr></em>' and '<em><adj-hop-ip-addr></em>')
755  * can be IPv4 or IPv6, but all must be of the same form in a single
756  * command. To display the current set of routes, use the commands
757  * '<em>show ip fib</em>' and '<em>show ip6 fib</em>'.
758  *
759  * @cliexpar
760  * Example of how to add a straight forward static route:
761  * @cliexcmd{ip route add 6.0.1.2/32 via 6.0.0.1 GigabitEthernet2/0/0}
762  * Example of how to delete a straight forward static route:
763  * @cliexcmd{ip route del 6.0.1.2/32 via 6.0.0.1 GigabitEthernet2/0/0}
764  * Mainly for route add/del performance testing, one can add or delete
765  * multiple routes by adding 'count N' to the previous item:
766  * @cliexcmd{ip route add count 10 7.0.0.0/24 via 6.0.0.1 GigabitEthernet2/0/0}
767  * Add multiple routes for the same destination to create equal-cost multipath:
768  * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.1 GigabitEthernet2/0/0}
769  * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0}
770  * For unequal-cost multipath, specify the desired weights. This
771  * combination of weights results in 3/4 of the traffic following the
772  * second path, 1/4 following the first path:
773  * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.1 GigabitEthernet2/0/0 weight 1}
774  * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0 weight 3}
775  * To add a route to a particular FIB table (VRF), use:
776  * @cliexcmd{ip route add 172.16.24.0/24 table 7 via GigabitEthernet2/0/0}
777  ?*/
778 /* *INDENT-OFF* */
779 VLIB_CLI_COMMAND (ip_route_command, static) = {
780   .path = "ip route",
781   .short_help = "ip route [add|del] [count <n>] <dst-ip-addr>/<width> [table <table-id>] [via <next-hop-ip-addr> [<interface>] [weight <weight>]] | [via arp <interface> <adj-hop-ip-addr>] | [via drop|punt|local<id>|arp|classify <classify-idx>] [lookup in table <out-table-id>]",
782   .function = vnet_ip_route_cmd,
783   .is_mp_safe = 1,
784 };
785 /* *INDENT-ON* */
786
787 clib_error_t *
788 vnet_ip_mroute_cmd (vlib_main_t * vm,
789                     unformat_input_t * main_input, vlib_cli_command_t * cmd)
790 {
791   unformat_input_t _line_input, *line_input = &_line_input;
792   clib_error_t *error = NULL;
793   fib_route_path_t rpath;
794   u32 table_id, is_del;
795   vnet_main_t *vnm;
796   mfib_prefix_t pfx;
797   u32 fib_index;
798   mfib_itf_flags_t iflags = 0;
799   mfib_entry_flags_t eflags = 0;
800   u32 gcount, scount, ss, gg, incr;
801   f64 timet[2];
802
803   gcount = scount = 1;
804   vnm = vnet_get_main ();
805   is_del = 0;
806   table_id = 0;
807   memset (&pfx, 0, sizeof (pfx));
808   memset (&rpath, 0, sizeof (rpath));
809   rpath.frp_sw_if_index = ~0;
810
811   /* Get a line of input. */
812   if (!unformat_user (main_input, unformat_line_input, line_input))
813     return 0;
814
815   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
816     {
817       if (unformat (line_input, "table %d", &table_id))
818         ;
819       else if (unformat (line_input, "del"))
820         is_del = 1;
821       else if (unformat (line_input, "add"))
822         is_del = 0;
823       else if (unformat (line_input, "scount %d", &scount))
824         ;
825       else if (unformat (line_input, "gcount %d", &gcount))
826         ;
827       else if (unformat (line_input, "%U %U",
828                          unformat_ip4_address,
829                          &pfx.fp_src_addr.ip4,
830                          unformat_ip4_address, &pfx.fp_grp_addr.ip4))
831         {
832           pfx.fp_proto = FIB_PROTOCOL_IP4;
833           pfx.fp_len = 64;
834         }
835       else if (unformat (line_input, "%U %U",
836                          unformat_ip6_address,
837                          &pfx.fp_src_addr.ip6,
838                          unformat_ip6_address, &pfx.fp_grp_addr.ip6))
839         {
840           pfx.fp_proto = FIB_PROTOCOL_IP6;
841           pfx.fp_len = 256;
842         }
843       else if (unformat (line_input, "%U/%d",
844                          unformat_ip4_address,
845                          &pfx.fp_grp_addr.ip4, &pfx.fp_len))
846         {
847           pfx.fp_proto = FIB_PROTOCOL_IP4;
848         }
849       else if (unformat (line_input, "%U/%d",
850                          unformat_ip6_address,
851                          &pfx.fp_grp_addr.ip6, &pfx.fp_len))
852         {
853           pfx.fp_proto = FIB_PROTOCOL_IP6;
854         }
855       else if (unformat (line_input, "%U",
856                          unformat_ip4_address, &pfx.fp_grp_addr.ip4))
857         {
858           memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4));
859           pfx.fp_proto = FIB_PROTOCOL_IP4;
860           pfx.fp_len = 32;
861         }
862       else if (unformat (line_input, "%U",
863                          unformat_ip6_address, &pfx.fp_grp_addr.ip6))
864         {
865           memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6));
866           pfx.fp_proto = FIB_PROTOCOL_IP6;
867           pfx.fp_len = 128;
868         }
869       else if (unformat (line_input, "via %U",
870                          unformat_vnet_sw_interface, vnm,
871                          &rpath.frp_sw_if_index))
872         {
873           rpath.frp_weight = 1;
874           rpath.frp_proto = FIB_PROTOCOL_IP4;
875         }
876       else if (unformat (line_input, "%U", unformat_mfib_itf_flags, &iflags))
877         ;
878       else if (unformat (line_input, "%U",
879                          unformat_mfib_entry_flags, &eflags))
880         ;
881       else
882         {
883           error = unformat_parse_error (line_input);
884           goto done;
885         }
886     }
887
888   if (~0 == table_id)
889     {
890       /*
891        * if no table_id is passed we will manipulate the default
892        */
893       fib_index = 0;
894     }
895   else
896     {
897       fib_index = mfib_table_find (pfx.fp_proto, table_id);
898
899       if (~0 == fib_index)
900         {
901           error = clib_error_return (0, "Nonexistent table id %d", table_id);
902           goto done;
903         }
904     }
905
906   timet[0] = vlib_time_now (vm);
907
908   if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
909     {
910       incr = 1 << (32 - (pfx.fp_len % 32));
911     }
912   else
913     {
914       incr = 1 << (128 - (pfx.fp_len % 128));
915     }
916
917   for (ss = 0; ss < scount; ss++)
918     {
919       for (gg = 0; gg < gcount; gg++)
920         {
921           if (is_del && 0 == rpath.frp_weight)
922             {
923               /* no path provided => route delete */
924               mfib_table_entry_delete (fib_index, &pfx, MFIB_SOURCE_CLI);
925             }
926           else if (eflags)
927             {
928               mfib_table_entry_update (fib_index, &pfx, MFIB_SOURCE_CLI,
929                                        eflags);
930             }
931           else
932             {
933               if (is_del)
934                 mfib_table_entry_path_remove (fib_index,
935                                               &pfx, MFIB_SOURCE_CLI, &rpath);
936               else
937                 mfib_table_entry_path_update (fib_index,
938                                               &pfx, MFIB_SOURCE_CLI, &rpath,
939                                               iflags);
940             }
941
942           if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
943             {
944               pfx.fp_grp_addr.ip4.as_u32 =
945                 clib_host_to_net_u32 (incr +
946                                       clib_net_to_host_u32 (pfx.
947                                                             fp_grp_addr.ip4.
948                                                             as_u32));
949             }
950           else
951             {
952               int bucket = (incr < 64 ? 0 : 1);
953               pfx.fp_grp_addr.ip6.as_u64[bucket] =
954                 clib_host_to_net_u64 (incr +
955                                       clib_net_to_host_u64 (pfx.
956                                                             fp_grp_addr.ip6.as_u64
957                                                             [bucket]));
958
959             }
960         }
961       if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
962         {
963           pfx.fp_src_addr.ip4.as_u32 =
964             clib_host_to_net_u32 (1 +
965                                   clib_net_to_host_u32 (pfx.fp_src_addr.
966                                                         ip4.as_u32));
967         }
968       else
969         {
970           pfx.fp_src_addr.ip6.as_u64[1] =
971             clib_host_to_net_u64 (1 +
972                                   clib_net_to_host_u64 (pfx.fp_src_addr.
973                                                         ip6.as_u64[1]));
974         }
975     }
976
977   timet[1] = vlib_time_now (vm);
978
979   if (scount > 1 || gcount > 1)
980     vlib_cli_output (vm, "%.6e routes/sec",
981                      (scount * gcount) / (timet[1] - timet[0]));
982
983 done:
984   unformat_free (line_input);
985
986   return error;
987 }
988
989 /*?
990  * This command is used to add or delete IPv4 or IPv6  multicastroutes. All
991  * IP Addresses ('<em><dst-ip-addr>/<width></em>',
992  * '<em><next-hop-ip-addr></em>' and '<em><adj-hop-ip-addr></em>')
993  * can be IPv4 or IPv6, but all must be of the same form in a single
994  * command. To display the current set of routes, use the commands
995  * '<em>show ip mfib</em>' and '<em>show ip6 mfib</em>'.
996  * The full set of support flags for interfaces and route is shown via;
997  * '<em>show mfib route flags</em>' and '<em>show mfib itf flags</em>'
998  * respectively.
999  * @cliexpar
1000  * Example of how to add a forwarding interface to a route (and create the
1001  * route if it does not exist)
1002  * @cliexcmd{ip mroute add 232.1.1.1 via GigabitEthernet2/0/0 Forward}
1003  * Example of how to add an accepting interface to a route (and create the
1004  * route if it does not exist)
1005  * @cliexcmd{ip mroute add 232.1.1.1 via GigabitEthernet2/0/1 Accept}
1006  * Example of changing the route's flags to send signals via the API
1007  * @cliexcmd{ip mroute add 232.1.1.1 Signal}
1008
1009  ?*/
1010 /* *INDENT-OFF* */
1011 VLIB_CLI_COMMAND (ip_mroute_command, static) =
1012 {
1013   .path = "ip mroute",
1014   .short_help = "ip mroute [add|del] <dst-ip-addr>/<width> [table <table-id>] [via <next-hop-ip-addr> [<interface>],",
1015   .function = vnet_ip_mroute_cmd,
1016   .is_mp_safe = 1,
1017 };
1018 /* *INDENT-ON* */
1019
1020 /*
1021  * The next two routines address a longstanding script hemorrhoid.
1022  * Probing a v4 or v6 neighbor needs to appear to be synchronous,
1023  * or dependent route-adds will simply fail.
1024  */
1025 static clib_error_t *
1026 ip6_probe_neighbor_wait (vlib_main_t * vm, ip6_address_t * a, u32 sw_if_index,
1027                          int retry_count)
1028 {
1029   vnet_main_t *vnm = vnet_get_main ();
1030   clib_error_t *e;
1031   int i;
1032   int resolved = 0;
1033   uword event_type;
1034   uword *event_data = 0;
1035
1036   ASSERT (vlib_in_process_context (vm));
1037
1038   if (retry_count > 0)
1039     vnet_register_ip6_neighbor_resolution_event
1040       (vnm, a, vlib_get_current_process (vm)->node_runtime.node_index,
1041        1 /* event */ , 0 /* data */ );
1042
1043   for (i = 0; i < retry_count; i++)
1044     {
1045       /* The interface may be down, etc. */
1046       e = ip6_probe_neighbor (vm, a, sw_if_index);
1047
1048       if (e)
1049         return e;
1050
1051       vlib_process_wait_for_event_or_clock (vm, 1.0);
1052       event_type = vlib_process_get_events (vm, &event_data);
1053       switch (event_type)
1054         {
1055         case 1:         /* resolved... */
1056           vlib_cli_output (vm, "Resolved %U", format_ip6_address, a);
1057           resolved = 1;
1058           goto done;
1059
1060         case ~0:                /* timeout */
1061           break;
1062
1063         default:
1064           clib_warning ("unknown event_type %d", event_type);
1065         }
1066       vec_reset_length (event_data);
1067     }
1068
1069 done:
1070
1071   if (!resolved)
1072     return clib_error_return (0, "Resolution failed for %U",
1073                               format_ip6_address, a);
1074   return 0;
1075 }
1076
1077 static clib_error_t *
1078 ip4_probe_neighbor_wait (vlib_main_t * vm, ip4_address_t * a, u32 sw_if_index,
1079                          int retry_count)
1080 {
1081   vnet_main_t *vnm = vnet_get_main ();
1082   clib_error_t *e;
1083   int i;
1084   int resolved = 0;
1085   uword event_type;
1086   uword *event_data = 0;
1087
1088   ASSERT (vlib_in_process_context (vm));
1089
1090   if (retry_count > 0)
1091     vnet_register_ip4_arp_resolution_event
1092       (vnm, a, vlib_get_current_process (vm)->node_runtime.node_index,
1093        1 /* event */ , 0 /* data */ );
1094
1095   for (i = 0; i < retry_count; i++)
1096     {
1097       /* The interface may be down, etc. */
1098       e = ip4_probe_neighbor (vm, a, sw_if_index);
1099
1100       if (e)
1101         return e;
1102
1103       vlib_process_wait_for_event_or_clock (vm, 1.0);
1104       event_type = vlib_process_get_events (vm, &event_data);
1105       switch (event_type)
1106         {
1107         case 1:         /* resolved... */
1108           vlib_cli_output (vm, "Resolved %U", format_ip4_address, a);
1109           resolved = 1;
1110           goto done;
1111
1112         case ~0:                /* timeout */
1113           break;
1114
1115         default:
1116           clib_warning ("unknown event_type %d", event_type);
1117         }
1118       vec_reset_length (event_data);
1119     }
1120
1121 done:
1122
1123   vec_reset_length (event_data);
1124
1125   if (!resolved)
1126     return clib_error_return (0, "Resolution failed for %U",
1127                               format_ip4_address, a);
1128   return 0;
1129 }
1130
1131 static clib_error_t *
1132 probe_neighbor_address (vlib_main_t * vm,
1133                         unformat_input_t * input, vlib_cli_command_t * cmd)
1134 {
1135   vnet_main_t *vnm = vnet_get_main ();
1136   unformat_input_t _line_input, *line_input = &_line_input;
1137   ip4_address_t a4;
1138   ip6_address_t a6;
1139   clib_error_t *error = 0;
1140   u32 sw_if_index = ~0;
1141   int retry_count = 3;
1142   int is_ip4 = 1;
1143   int address_set = 0;
1144
1145   /* Get a line of input. */
1146   if (!unformat_user (input, unformat_line_input, line_input))
1147     return 0;
1148
1149   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1150     {
1151       if (unformat_user (line_input, unformat_vnet_sw_interface, vnm,
1152                          &sw_if_index))
1153         ;
1154       else if (unformat (line_input, "retry %d", &retry_count))
1155         ;
1156
1157       else if (unformat (line_input, "%U", unformat_ip4_address, &a4))
1158         address_set++;
1159       else if (unformat (line_input, "%U", unformat_ip6_address, &a6))
1160         {
1161           address_set++;
1162           is_ip4 = 0;
1163         }
1164       else
1165         {
1166           error = clib_error_return (0, "unknown input '%U'",
1167                                      format_unformat_error, line_input);
1168           goto done;
1169         }
1170     }
1171
1172   if (sw_if_index == ~0)
1173     {
1174       error = clib_error_return (0, "Interface required, not set.");
1175       goto done;
1176     }
1177   if (address_set == 0)
1178     {
1179       error = clib_error_return (0, "ip address required, not set.");
1180       goto done;
1181     }
1182   if (address_set > 1)
1183     {
1184       error = clib_error_return (0, "Multiple ip addresses not supported.");
1185       goto done;
1186     }
1187
1188   if (is_ip4)
1189     error = ip4_probe_neighbor_wait (vm, &a4, sw_if_index, retry_count);
1190   else
1191     error = ip6_probe_neighbor_wait (vm, &a6, sw_if_index, retry_count);
1192
1193 done:
1194   unformat_free (line_input);
1195
1196   return error;
1197 }
1198
1199 /*?
1200  * The '<em>ip probe-neighbor</em>' command ARPs for IPv4 addresses or
1201  * attempts IPv6 neighbor discovery depending on the supplied IP address
1202  * format.
1203  *
1204  * @note This command will not immediately affect the indicated FIB; it
1205  * is not suitable for use in establishing a FIB entry prior to adding
1206  * recursive FIB entries. As in: don't use it in a script to probe a
1207  * gateway prior to adding a default route. It won't work. Instead,
1208  * configure a static ARP cache entry [see '<em>set ip arp</em>'], or
1209  * a static IPv6 neighbor [see '<em>set ip6 neighbor</em>'].
1210  *
1211  * @cliexpar
1212  * Example of probe for an IPv4 address:
1213  * @cliexcmd{ip probe-neighbor GigabitEthernet2/0/0 172.16.1.2}
1214 ?*/
1215 /* *INDENT-OFF* */
1216 VLIB_CLI_COMMAND (ip_probe_neighbor_command, static) = {
1217   .path = "ip probe-neighbor",
1218   .function = probe_neighbor_address,
1219   .short_help = "ip probe-neighbor <interface> <ip4-addr> | <ip6-addr> [retry nn]",
1220   .is_mp_safe = 1,
1221 };
1222 /* *INDENT-ON* */
1223
1224 /*
1225  * fd.io coding-style-patch-verification: ON
1226  *
1227  * Local Variables:
1228  * eval: (c-set-style "gnu")
1229  * End:
1230  */