ip-neighbor: Use ip_address_t rather than ip46_address_t
[vpp.git] / src / vnet / ip-neighbor / ip_neighbor.c
1 /*
2  * src/vnet/ip/ip_neighboor.c: ip neighbor generic handling
3  *
4  * Copyright (c) 2018 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <vppinfra/llist.h>
19
20 #include <vnet/ip-neighbor/ip_neighbor.h>
21 #include <vnet/ip-neighbor/ip4_neighbor.h>
22 #include <vnet/ip-neighbor/ip6_neighbor.h>
23 #include <vnet/ip-neighbor/ip_neighbor_watch.h>
24
25 #include <vnet/ip/ip6_ll_table.h>
26 #include <vnet/fib/fib_table.h>
27 #include <vnet/adj/adj_mcast.h>
28
29 /** Pool for All IP neighbors */
30 static ip_neighbor_t *ip_neighbor_pool;
31
32 /** protocol specific lists of time sorted neighbors */
33 index_t ip_neighbor_list_head[N_AF];
34
35 typedef struct ip_neighbor_elt_t_
36 {
37   clib_llist_anchor_t ipne_anchor;
38   index_t ipne_index;
39 } ip_neighbor_elt_t;
40
41 /** Pool of linked list elemeents */
42 ip_neighbor_elt_t *ip_neighbor_elt_pool;
43
44 typedef struct ip_neighbor_db_t_
45 {
46   /** per interface hash */
47   uword **ipndb_hash;
48   /** per-protocol limit - max number of neighbors*/
49   u32 ipndb_limit;
50   /** max age of a neighbor before it's forcibly evicted */
51   u32 ipndb_age;
52   /** when the limit is reached and new neighbors are created, should
53    * we recycle an old one */
54   bool ipndb_recycle;
55   /** per-protocol number of elements */
56   u32 ipndb_n_elts;
57   /** per-protocol number of elements per-fib-index*/
58   u32 *ipndb_n_elts_per_fib;
59 } ip_neighbor_db_t;
60
61 static vlib_log_class_t ipn_logger;
62
63 /* DBs of neighbours one per AF */
64 /* *INDENT-OFF* */
65 static ip_neighbor_db_t ip_neighbor_db[N_AF] = {
66   [AF_IP4] = {
67     .ipndb_limit = 50000,
68     /* Default to not aging and not recycling */
69     .ipndb_age = 0,
70     .ipndb_recycle = false,
71   },
72   [AF_IP6] = {
73     .ipndb_limit = 50000,
74     /* Default to not aging and not recycling */
75     .ipndb_age = 0,
76     .ipndb_recycle = false,
77   }
78 };
79 /* *INDENT-ON* */
80
81 #define IP_NEIGHBOR_DBG(...)                           \
82     vlib_log_debug (ipn_logger, __VA_ARGS__);
83
84 #define IP_NEIGHBOR_INFO(...)                          \
85     vlib_log_notice (ipn_logger, __VA_ARGS__);
86
87 ip_neighbor_t *
88 ip_neighbor_get (index_t ipni)
89 {
90   if (pool_is_free_index (ip_neighbor_pool, ipni))
91     return (NULL);
92
93   return (pool_elt_at_index (ip_neighbor_pool, ipni));
94 }
95
96 static index_t
97 ip_neighbor_get_index (const ip_neighbor_t * ipn)
98 {
99   return (ipn - ip_neighbor_pool);
100 }
101
102 static void
103 ip_neighbor_touch (ip_neighbor_t * ipn)
104 {
105   ipn->ipn_flags &= ~IP_NEIGHBOR_FLAG_STALE;
106 }
107
108 static bool
109 ip_neighbor_is_dynamic (const ip_neighbor_t * ipn)
110 {
111   return (ipn->ipn_flags & IP_NEIGHBOR_FLAG_DYNAMIC);
112 }
113
114 const ip_address_t *
115 ip_neighbor_get_ip (const ip_neighbor_t * ipn)
116 {
117   return (&ipn->ipn_key->ipnk_ip);
118 }
119
120 ip_address_family_t
121 ip_neighbor_get_af (const ip_neighbor_t * ipn)
122 {
123   return (ip_addr_version (&ipn->ipn_key->ipnk_ip));
124 }
125
126 const mac_address_t *
127 ip_neighbor_get_mac (const ip_neighbor_t * ipn)
128 {
129   return (&ipn->ipn_mac);
130 }
131
132 const u32
133 ip_neighbor_get_sw_if_index (const ip_neighbor_t * ipn)
134 {
135   return (ipn->ipn_key->ipnk_sw_if_index);
136 }
137
138 static void
139 ip_neighbor_list_remove (ip_neighbor_t * ipn)
140 {
141   /* new neighbours, are added to the head of the list, since the
142    * list is time sorted, newest first */
143   ip_neighbor_elt_t *elt;
144
145   if (~0 != ipn->ipn_elt)
146     {
147       elt = pool_elt_at_index (ip_neighbor_elt_pool, ipn->ipn_elt);
148
149       clib_llist_remove (ip_neighbor_elt_pool, ipne_anchor, elt);
150
151       ipn->ipn_elt = ~0;
152     }
153 }
154
155 static void
156 ip_neighbor_refresh (ip_neighbor_t * ipn)
157 {
158   /* new neighbours, are added to the head of the list, since the
159    * list is time sorted, newest first */
160   ip_neighbor_elt_t *elt, *head;
161
162   ip_neighbor_touch (ipn);
163   ipn->ipn_time_last_updated = vlib_time_now (vlib_get_main ());
164   ipn->ipn_n_probes = 0;
165
166   if (ip_neighbor_is_dynamic (ipn))
167     {
168       if (~0 == ipn->ipn_elt)
169         /* first time insertion */
170         pool_get_zero (ip_neighbor_elt_pool, elt);
171       else
172         {
173           /* already inserted - extract first */
174           elt = pool_elt_at_index (ip_neighbor_elt_pool, ipn->ipn_elt);
175
176           clib_llist_remove (ip_neighbor_elt_pool, ipne_anchor, elt);
177         }
178       head = pool_elt_at_index (ip_neighbor_elt_pool,
179                                 ip_neighbor_list_head[ip_neighbor_get_af
180                                                       (ipn)]);
181
182       elt->ipne_index = ip_neighbor_get_index (ipn);
183       clib_llist_add (ip_neighbor_elt_pool, ipne_anchor, elt, head);
184       ipn->ipn_elt = elt - ip_neighbor_elt_pool;
185     }
186 }
187
188 static void
189 ip_neighbor_db_add (const ip_neighbor_t * ipn)
190 {
191   ip_address_family_t af;
192   u32 sw_if_index;
193
194   af = ip_neighbor_get_af (ipn);
195   sw_if_index = ipn->ipn_key->ipnk_sw_if_index;
196
197   vec_validate (ip_neighbor_db[af].ipndb_hash, sw_if_index);
198
199   if (!ip_neighbor_db[af].ipndb_hash[sw_if_index])
200     ip_neighbor_db[af].ipndb_hash[sw_if_index]
201       = hash_create_mem (0, sizeof (ip_neighbor_key_t), sizeof (index_t));
202
203   hash_set_mem (ip_neighbor_db[af].ipndb_hash[sw_if_index],
204                 ipn->ipn_key, ip_neighbor_get_index (ipn));
205
206   ip_neighbor_db[af].ipndb_n_elts++;
207 }
208
209 static void
210 ip_neighbor_db_remove (const ip_neighbor_t * ipn)
211 {
212   ip_address_family_t af;
213   u32 sw_if_index;
214
215   af = ip_neighbor_get_af (ipn);
216   sw_if_index = ipn->ipn_key->ipnk_sw_if_index;
217
218   vec_validate (ip_neighbor_db[af].ipndb_hash, sw_if_index);
219
220   hash_unset_mem (ip_neighbor_db[af].ipndb_hash[sw_if_index], ipn->ipn_key);
221
222   ip_neighbor_db[af].ipndb_n_elts--;
223 }
224
225 static ip_neighbor_t *
226 ip_neighbor_db_find (const ip_neighbor_key_t * key)
227 {
228   ip_address_family_t af;
229   uword *p;
230
231   af = ip_addr_version (&key->ipnk_ip);
232
233   if (key->ipnk_sw_if_index >= vec_len (ip_neighbor_db[af].ipndb_hash))
234     return NULL;
235
236   p = hash_get_mem (ip_neighbor_db[af].ipndb_hash
237                     [key->ipnk_sw_if_index], key);
238
239   if (p)
240     return ip_neighbor_get (p[0]);
241
242   return (NULL);
243 }
244
245 static u8
246 ip_af_type_pfx_len (ip_address_family_t type)
247 {
248   return (type == AF_IP4 ? 32 : 128);
249 }
250
251 static void
252 ip_neighbor_adj_fib_add (ip_neighbor_t * ipn, u32 fib_index)
253 {
254   ip_address_family_t af;
255
256   af = ip_neighbor_get_af (ipn);
257
258   if (af == AF_IP6 &&
259       ip6_address_is_link_local_unicast (&ip_addr_v6
260                                          (&ipn->ipn_key->ipnk_ip)))
261     {
262       ip6_ll_prefix_t pfx = {
263         .ilp_addr = ip_addr_v6 (&ipn->ipn_key->ipnk_ip),
264         .ilp_sw_if_index = ipn->ipn_key->ipnk_sw_if_index,
265       };
266       ipn->ipn_fib_entry_index =
267         ip6_ll_table_entry_update (&pfx, FIB_ROUTE_PATH_FLAG_NONE);
268     }
269   else
270     {
271       fib_protocol_t fproto;
272
273       fproto = ip_address_family_to_fib_proto (af);
274
275       fib_prefix_t pfx = {
276         .fp_len = ip_af_type_pfx_len (af),
277         .fp_proto = fproto,
278         .fp_addr = ip_addr_46 (&ipn->ipn_key->ipnk_ip),
279       };
280
281       ipn->ipn_fib_entry_index =
282         fib_table_entry_path_add (fib_index, &pfx, FIB_SOURCE_ADJ,
283                                   FIB_ENTRY_FLAG_ATTACHED,
284                                   fib_proto_to_dpo (fproto),
285                                   &pfx.fp_addr,
286                                   ipn->ipn_key->ipnk_sw_if_index,
287                                   ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
288
289       vec_validate (ip_neighbor_db[af].ipndb_n_elts_per_fib, fib_index);
290
291       ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index]++;
292
293       if (1 == ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index])
294         fib_table_lock (fib_index, fproto, FIB_SOURCE_ADJ);
295     }
296 }
297
298 static void
299 ip_neighbor_adj_fib_remove (ip_neighbor_t * ipn, u32 fib_index)
300 {
301   ip_address_family_t af;
302
303   af = ip_neighbor_get_af (ipn);
304
305   if (FIB_NODE_INDEX_INVALID != ipn->ipn_fib_entry_index)
306     {
307       if (AF_IP6 == af &&
308           ip6_address_is_link_local_unicast (&ip_addr_v6
309                                              (&ipn->ipn_key->ipnk_ip)))
310         {
311           ip6_ll_prefix_t pfx = {
312             .ilp_addr = ip_addr_v6 (&ipn->ipn_key->ipnk_ip),
313             .ilp_sw_if_index = ipn->ipn_key->ipnk_sw_if_index,
314           };
315           ip6_ll_table_entry_delete (&pfx);
316         }
317       else
318         {
319           fib_protocol_t fproto;
320
321           fproto = ip_address_family_to_fib_proto (af);
322
323           fib_prefix_t pfx = {
324             .fp_len = ip_af_type_pfx_len (af),
325             .fp_proto = fproto,
326             .fp_addr = ip_addr_46 (&ipn->ipn_key->ipnk_ip),
327           };
328
329           fib_table_entry_path_remove (fib_index,
330                                        &pfx,
331                                        FIB_SOURCE_ADJ,
332                                        fib_proto_to_dpo (fproto),
333                                        &pfx.fp_addr,
334                                        ipn->ipn_key->ipnk_sw_if_index,
335                                        ~0, 1, FIB_ROUTE_PATH_FLAG_NONE);
336
337           ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index]--;
338
339           if (0 == ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index])
340             fib_table_unlock (fib_index, fproto, FIB_SOURCE_ADJ);
341         }
342     }
343 }
344
345 static void
346 ip_neighbor_mk_complete (adj_index_t ai, ip_neighbor_t * ipn)
347 {
348   adj_nbr_update_rewrite (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE,
349                           ethernet_build_rewrite (vnet_get_main (),
350                                                   ipn->
351                                                   ipn_key->ipnk_sw_if_index,
352                                                   adj_get_link_type (ai),
353                                                   ipn->ipn_mac.bytes));
354 }
355
356 static void
357 ip_neighbor_mk_incomplete (adj_index_t ai)
358 {
359   ip_adjacency_t *adj = adj_get (ai);
360
361   adj_nbr_update_rewrite (ai,
362                           ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
363                           ethernet_build_rewrite (vnet_get_main (),
364                                                   adj->
365                                                   rewrite_header.sw_if_index,
366                                                   VNET_LINK_ARP,
367                                                   VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
368 }
369
370 static adj_walk_rc_t
371 ip_neighbor_mk_complete_walk (adj_index_t ai, void *ctx)
372 {
373   ip_neighbor_t *ipn = ctx;
374
375   ip_neighbor_mk_complete (ai, ipn);
376
377   return (ADJ_WALK_RC_CONTINUE);
378 }
379
380 static adj_walk_rc_t
381 ip_neighbor_mk_incomplete_walk (adj_index_t ai, void *ctx)
382 {
383   ip_neighbor_mk_incomplete (ai);
384
385   return (ADJ_WALK_RC_CONTINUE);
386 }
387
388 static void
389 ip_neighbor_free (ip_neighbor_t * ipn)
390 {
391   ip_address_family_t af;
392
393   af = ip_neighbor_get_af (ipn);
394
395   IP_NEIGHBOR_DBG ("free: %U", format_ip_neighbor,
396                    ip_neighbor_get_index (ipn));
397
398   adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
399                    ip_address_family_to_fib_proto (af),
400                    &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
401                    ip_neighbor_mk_incomplete_walk, ipn);
402   ip_neighbor_adj_fib_remove
403     (ipn,
404      fib_table_get_index_for_sw_if_index
405      (ip_address_family_to_fib_proto (af), ipn->ipn_key->ipnk_sw_if_index));
406
407   ip_neighbor_list_remove (ipn);
408   ip_neighbor_db_remove (ipn);
409   clib_mem_free (ipn->ipn_key);
410
411   pool_put (ip_neighbor_pool, ipn);
412 }
413
414 static bool
415 ip_neighbor_force_reuse (ip_address_family_t af)
416 {
417   if (!ip_neighbor_db[af].ipndb_recycle)
418     return false;
419
420   /* pluck the oldest entry, which is the one from the end of the list */
421   ip_neighbor_elt_t *elt, *head;
422
423   head = pool_elt_at_index (ip_neighbor_elt_pool, ip_neighbor_list_head[af]);
424
425   if (clib_llist_is_empty (ip_neighbor_elt_pool, ipne_anchor, head))
426     return (false);
427
428   elt = clib_llist_prev (ip_neighbor_elt_pool, ipne_anchor, head);
429   ip_neighbor_free (ip_neighbor_get (elt->ipne_index));
430
431   return (true);
432 }
433
434 static ip_neighbor_t *
435 ip_neighbor_alloc (const ip_neighbor_key_t * key,
436                    const mac_address_t * mac, ip_neighbor_flags_t flags)
437 {
438   ip_address_family_t af;
439   ip_neighbor_t *ipn;
440
441   af = ip_addr_version (&key->ipnk_ip);
442
443   if (ip_neighbor_db[af].ipndb_limit &&
444       (ip_neighbor_db[af].ipndb_n_elts >= ip_neighbor_db[af].ipndb_limit))
445     {
446       if (!ip_neighbor_force_reuse (af))
447         return (NULL);
448     }
449
450   pool_get_zero (ip_neighbor_pool, ipn);
451
452   ipn->ipn_key = clib_mem_alloc (sizeof (*ipn->ipn_key));
453   clib_memcpy (ipn->ipn_key, key, sizeof (*ipn->ipn_key));
454
455   ipn->ipn_fib_entry_index = FIB_NODE_INDEX_INVALID;
456   ipn->ipn_flags = flags;
457   ipn->ipn_elt = ~0;
458
459   mac_address_copy (&ipn->ipn_mac, mac);
460
461   ip_neighbor_db_add (ipn);
462
463   /* create the adj-fib. the entry in the FIB table for the peer's interface */
464   if (!(ipn->ipn_flags & IP_NEIGHBOR_FLAG_NO_FIB_ENTRY))
465     ip_neighbor_adj_fib_add
466       (ipn, fib_table_get_index_for_sw_if_index
467        (ip_address_family_to_fib_proto (af), ipn->ipn_key->ipnk_sw_if_index));
468
469   return (ipn);
470 }
471
472 int
473 ip_neighbor_add (const ip_address_t * ip,
474                  const mac_address_t * mac,
475                  u32 sw_if_index,
476                  ip_neighbor_flags_t flags, u32 * stats_index)
477 {
478   fib_protocol_t fproto;
479   ip_neighbor_t *ipn;
480
481   /* main thread only */
482   ASSERT (0 == vlib_get_thread_index ());
483
484   fproto = ip_address_family_to_fib_proto (ip_addr_version (ip));
485
486   const ip_neighbor_key_t key = {
487     .ipnk_ip = *ip,
488     .ipnk_sw_if_index = sw_if_index,
489   };
490
491   ipn = ip_neighbor_db_find (&key);
492
493   if (ipn)
494     {
495       IP_NEIGHBOR_DBG ("update: %U, %U",
496                        format_vnet_sw_if_index_name, vnet_get_main (),
497                        sw_if_index, format_ip_address, ip,
498                        format_ip_neighbor_flags, flags, format_mac_address_t,
499                        mac);
500
501       ip_neighbor_touch (ipn);
502
503       /* Refuse to over-write static neighbor entry. */
504       if (!(flags & IP_NEIGHBOR_FLAG_STATIC) &&
505           (ipn->ipn_flags & IP_NEIGHBOR_FLAG_STATIC))
506         {
507           /* if MAC address match, still check to send event */
508           if (0 == mac_address_cmp (&ipn->ipn_mac, mac))
509             goto check_customers;
510           return -2;
511         }
512
513       /* A dynamic entry can become static, but not vice-versa.
514        * i.e. since if it was programmed by the CP then it must
515        * be removed by the CP */
516       if ((flags & IP_NEIGHBOR_FLAG_STATIC) &&
517           !(ipn->ipn_flags & IP_NEIGHBOR_FLAG_STATIC))
518         {
519           ip_neighbor_list_remove (ipn);
520           ipn->ipn_flags |= IP_NEIGHBOR_FLAG_STATIC;
521           ipn->ipn_flags &= ~IP_NEIGHBOR_FLAG_DYNAMIC;
522         }
523
524       /*
525        * prevent a DoS attack from the data-plane that
526        * spams us with no-op updates to the MAC address
527        */
528       if (0 == mac_address_cmp (&ipn->ipn_mac, mac))
529         {
530           ip_neighbor_refresh (ipn);
531           goto check_customers;
532         }
533
534       mac_address_copy (&ipn->ipn_mac, mac);
535     }
536   else
537     {
538       IP_NEIGHBOR_INFO ("add: %U, %U",
539                         format_vnet_sw_if_index_name, vnet_get_main (),
540                         sw_if_index, format_ip_address, ip,
541                         format_ip_neighbor_flags, flags, format_mac_address_t,
542                         mac);
543
544       ipn = ip_neighbor_alloc (&key, mac, flags);
545
546       if (NULL == ipn)
547         return VNET_API_ERROR_LIMIT_EXCEEDED;
548     }
549
550   /* Update time stamp and flags. */
551   ip_neighbor_refresh (ipn);
552
553   adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
554                    fproto, &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
555                    ip_neighbor_mk_complete_walk, ipn);
556
557 check_customers:
558   /* Customer(s) requesting event for this address? */
559   ip_neighbor_publish (ip_neighbor_get_index (ipn));
560
561   if (stats_index)
562     *stats_index = adj_nbr_find (fproto,
563                                  fib_proto_to_link (fproto),
564                                  &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
565                                  ipn->ipn_key->ipnk_sw_if_index);
566   return 0;
567 }
568
569 int
570 ip_neighbor_del (const ip_address_t * ip, u32 sw_if_index)
571 {
572   ip_neighbor_t *ipn;
573
574   /* main thread only */
575   ASSERT (0 == vlib_get_thread_index ());
576
577   IP_NEIGHBOR_INFO ("delete: %U, %U",
578                     format_vnet_sw_if_index_name, vnet_get_main (),
579                     sw_if_index, format_ip_address, ip);
580
581   const ip_neighbor_key_t key = {
582     .ipnk_ip = *ip,
583     .ipnk_sw_if_index = sw_if_index,
584   };
585
586   ipn = ip_neighbor_db_find (&key);
587
588   if (NULL == ipn)
589     return (VNET_API_ERROR_NO_SUCH_ENTRY);
590
591   ip_neighbor_free (ipn);
592
593   return (0);
594 }
595
596 typedef struct ip_neighbor_del_all_ctx_t_
597 {
598   index_t *ipn_del;
599 } ip_neighbor_del_all_ctx_t;
600
601 static walk_rc_t
602 ip_neighbor_del_all_walk_cb (index_t ipni, void *arg)
603 {
604   ip_neighbor_del_all_ctx_t *ctx = arg;
605
606   vec_add1 (ctx->ipn_del, ipni);
607
608   return (WALK_CONTINUE);
609 }
610
611 void
612 ip_neighbor_del_all (ip_address_family_t af, u32 sw_if_index)
613 {
614   IP_NEIGHBOR_INFO ("delete-all: %U, %U",
615                     format_ip_address_family, af,
616                     format_vnet_sw_if_index_name, vnet_get_main (),
617                     sw_if_index);
618
619   ip_neighbor_del_all_ctx_t ctx = {
620     .ipn_del = NULL,
621   };
622   index_t *ipni;
623
624   ip_neighbor_walk (af, sw_if_index, ip_neighbor_del_all_walk_cb, &ctx);
625
626   vec_foreach (ipni, ctx.ipn_del) ip_neighbor_free (ip_neighbor_get (*ipni));
627   vec_free (ctx.ipn_del);
628 }
629
630 void
631 ip_neighbor_update (vnet_main_t * vnm, adj_index_t ai)
632 {
633   ip_neighbor_t *ipn;
634   ip_adjacency_t *adj;
635
636   adj = adj_get (ai);
637
638   ip_neighbor_key_t key = {
639     .ipnk_sw_if_index = adj->rewrite_header.sw_if_index,
640   };
641
642   ip_address_from_46 (&adj->sub_type.nbr.next_hop,
643                       adj->ia_nh_proto, &key.ipnk_ip);
644
645   ipn = ip_neighbor_db_find (&key);
646
647   switch (adj->lookup_next_index)
648     {
649     case IP_LOOKUP_NEXT_ARP:
650       if (NULL != ipn)
651         {
652           adj_nbr_walk_nh (adj->rewrite_header.sw_if_index,
653                            adj->ia_nh_proto,
654                            &adj->sub_type.nbr.next_hop,
655                            ip_neighbor_mk_complete_walk, ipn);
656         }
657       else
658         {
659           /*
660            * no matching ARP entry.
661            * construct the rewrite required to for an ARP packet, and stick
662            * that in the adj's pipe to smoke.
663            */
664           adj_nbr_update_rewrite
665             (ai,
666              ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
667              ethernet_build_rewrite
668              (vnm,
669               adj->rewrite_header.sw_if_index,
670               VNET_LINK_ARP,
671               VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
672
673           /*
674            * since the FIB has added this adj for a route, it makes sense it
675            * may want to forward traffic sometime soon. Let's send a
676            * speculative ARP. just one. If we were to do periodically that
677            * wouldn't be bad either, but that's more code than i'm prepared to
678            * write at this time for relatively little reward.
679            */
680           /*
681            * adj_nbr_update_rewrite may actually call fib_walk_sync.
682            * fib_walk_sync may allocate a new adjacency and potentially cause
683            * a realloc for adj_pool. When that happens, adj pointer is no
684            * longer valid here.x We refresh adj pointer accordingly.
685            */
686           adj = adj_get (ai);
687           ip_neighbor_probe (adj);
688         }
689       break;
690     case IP_LOOKUP_NEXT_GLEAN:
691     case IP_LOOKUP_NEXT_BCAST:
692     case IP_LOOKUP_NEXT_MCAST:
693     case IP_LOOKUP_NEXT_DROP:
694     case IP_LOOKUP_NEXT_PUNT:
695     case IP_LOOKUP_NEXT_LOCAL:
696     case IP_LOOKUP_NEXT_REWRITE:
697     case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
698     case IP_LOOKUP_NEXT_MIDCHAIN:
699     case IP_LOOKUP_NEXT_ICMP_ERROR:
700     case IP_LOOKUP_N_NEXT:
701       ASSERT (0);
702       break;
703     }
704 }
705
706 void
707 ip_neighbor_learn (const ip_neighbor_learn_t * l)
708 {
709   ip_neighbor_add (&l->ip, &l->mac, l->sw_if_index,
710                    IP_NEIGHBOR_FLAG_DYNAMIC, NULL);
711 }
712
713 static clib_error_t *
714 ip_neighbor_cmd (vlib_main_t * vm,
715                  unformat_input_t * input, vlib_cli_command_t * cmd)
716 {
717   ip_address_t ip = IP_ADDRESS_V6_ALL_0S;
718   mac_address_t mac = ZERO_MAC_ADDRESS;
719   vnet_main_t *vnm = vnet_get_main ();
720   ip_neighbor_flags_t flags;
721   u32 sw_if_index = ~0;
722   int is_add = 1;
723   int count = 1;
724
725   flags = IP_NEIGHBOR_FLAG_DYNAMIC;
726
727   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
728     {
729       /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
730       if (unformat (input, "%U %U %U",
731                     unformat_vnet_sw_interface, vnm, &sw_if_index,
732                     unformat_ip_address, &ip, unformat_mac_address_t, &mac))
733         ;
734       else if (unformat (input, "delete") || unformat (input, "del"))
735         is_add = 0;
736       else if (unformat (input, "static"))
737         {
738           flags |= IP_NEIGHBOR_FLAG_STATIC;
739           flags &= ~IP_NEIGHBOR_FLAG_DYNAMIC;
740         }
741       else if (unformat (input, "no-fib-entry"))
742         flags |= IP_NEIGHBOR_FLAG_NO_FIB_ENTRY;
743       else if (unformat (input, "count %d", &count))
744         ;
745       else
746         break;
747     }
748
749   if (sw_if_index == ~0 ||
750       ip_address_is_zero (&ip) || mac_address_is_zero (&mac))
751     return clib_error_return (0,
752                               "specify interface, IP address and MAC: `%U'",
753                               format_unformat_error, input);
754
755   while (count)
756     {
757       if (is_add)
758         ip_neighbor_add (&ip, &mac, sw_if_index, flags, NULL);
759       else
760         ip_neighbor_del (&ip, sw_if_index);
761
762       ip_address_increment (&ip);
763       mac_address_increment (&mac);
764
765       --count;
766     }
767
768   return NULL;
769 }
770
771 /* *INDENT-OFF* */
772 /*?
773  * Add or delete IPv4 ARP cache entries.
774  *
775  * @note 'set ip neighbor' options (e.g. delete, static, 'fib-id <id>',
776  * 'count <number>', 'interface ip4_addr mac_addr') can be added in
777  * any order and combination.
778  *
779  * @cliexpar
780  * @parblock
781  * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
782  * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
783  * @cliexcmd{set ip neighbor GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
784  * @cliexcmd{set ip neighbor delete GigabitEthernet2/0/0 6.0.0.3 de:ad:be:ef:ba:be}
785  *
786  * To add or delete an IPv4 ARP cache entry to or from a specific fib
787  * table:
788  * @cliexcmd{set ip neighbor fib-id 1 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
789  * @cliexcmd{set ip neighbor fib-id 1 delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
790  *
791  * Add or delete IPv4 static ARP cache entries as follows:
792  * @cliexcmd{set ip neighbor static GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
793  * @cliexcmd{set ip neighbor static delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
794  *
795  * For testing / debugging purposes, the 'set ip neighbor' command can add or
796  * delete multiple entries. Supply the 'count N' parameter:
797  * @cliexcmd{set ip neighbor count 10 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
798  * @endparblock
799  ?*/
800 VLIB_CLI_COMMAND (ip_neighbor_command, static) = {
801   .path = "set ip neighbor",
802   .short_help =
803   "set ip neighbor [del] <intfc> <ip-address> <mac-address> [static] [no-fib-entry] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
804   .function = ip_neighbor_cmd,
805 };
806 VLIB_CLI_COMMAND (ip_neighbor_command2, static) = {
807   .path = "ip neighbor",
808   .short_help =
809   "ip neighbor [del] <intfc> <ip-address> <mac-address> [static] [no-fib-entry] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
810   .function = ip_neighbor_cmd,
811 };
812 /* *INDENT-ON* */
813
814 static int
815 ip_neighbor_sort (void *a1, void *a2)
816 {
817   index_t *ipni1 = a1, *ipni2 = a2;
818   ip_neighbor_t *ipn1, *ipn2;
819   int cmp;
820
821   ipn1 = ip_neighbor_get (*ipni1);
822   ipn2 = ip_neighbor_get (*ipni2);
823
824   cmp = vnet_sw_interface_compare (vnet_get_main (),
825                                    ipn1->ipn_key->ipnk_sw_if_index,
826                                    ipn2->ipn_key->ipnk_sw_if_index);
827   if (!cmp)
828     cmp = ip_address_cmp (&ipn1->ipn_key->ipnk_ip, &ipn2->ipn_key->ipnk_ip);
829   return cmp;
830 }
831
832 static index_t *
833 ip_neighbor_entries (u32 sw_if_index, ip_address_family_t af)
834 {
835   index_t *ipnis = NULL;
836   ip_neighbor_t *ipn;
837
838   /* *INDENT-OFF* */
839   pool_foreach (ipn, ip_neighbor_pool,
840   ({
841     if ((sw_if_index == ~0 ||
842         ipn->ipn_key->ipnk_sw_if_index == sw_if_index) &&
843         (N_AF == af ||
844          ip_neighbor_get_af(ipn) == af))
845        vec_add1 (ipnis, ip_neighbor_get_index(ipn));
846   }));
847
848   /* *INDENT-ON* */
849
850   if (ipnis)
851     vec_sort_with_function (ipnis, ip_neighbor_sort);
852   return ipnis;
853 }
854
855 static clib_error_t *
856 ip_neighbor_show_sorted_i (vlib_main_t * vm,
857                            unformat_input_t * input,
858                            vlib_cli_command_t * cmd, ip_address_family_t af)
859 {
860   ip_neighbor_elt_t *elt, *head;
861
862   head = pool_elt_at_index (ip_neighbor_elt_pool, ip_neighbor_list_head[af]);
863
864
865   vlib_cli_output (vm, "%=12s%=40s%=6s%=20s%=24s", "Time", "IP",
866                    "Flags", "Ethernet", "Interface");
867
868   /* *INDENT-OFF*/
869   /* the list is time sorted, newest first, so start from the back
870    * and work forwards. Stop when we get to one that is alive */
871   clib_llist_foreach_reverse(ip_neighbor_elt_pool,
872                              ipne_anchor, head, elt,
873   ({
874     vlib_cli_output (vm, "%U", format_ip_neighbor, elt->ipne_index);
875   }));
876   /* *INDENT-ON*/
877
878   return (NULL);
879 }
880
881 static clib_error_t *
882 ip_neighbor_show_i (vlib_main_t * vm,
883                     unformat_input_t * input,
884                     vlib_cli_command_t * cmd, ip_address_family_t af)
885 {
886   index_t *ipni, *ipnis = NULL;
887   u32 sw_if_index;
888
889   /* Filter entries by interface if given. */
890   sw_if_index = ~0;
891   (void) unformat_user (input, unformat_vnet_sw_interface, vnet_get_main (),
892                         &sw_if_index);
893
894   ipnis = ip_neighbor_entries (sw_if_index, af);
895
896   if (ipnis)
897     vlib_cli_output (vm, "%=12s%=40s%=6s%=20s%=24s", "Time", "IP",
898                      "Flags", "Ethernet", "Interface");
899
900   vec_foreach (ipni, ipnis)
901   {
902     vlib_cli_output (vm, "%U", format_ip_neighbor, *ipni);
903   }
904   vec_free (ipnis);
905
906   return (NULL);
907 }
908
909 static clib_error_t *
910 ip_neighbor_show (vlib_main_t * vm,
911                   unformat_input_t * input, vlib_cli_command_t * cmd)
912 {
913   return (ip_neighbor_show_i (vm, input, cmd, N_AF));
914 }
915
916 static clib_error_t *
917 ip6_neighbor_show (vlib_main_t * vm,
918                    unformat_input_t * input, vlib_cli_command_t * cmd)
919 {
920   return (ip_neighbor_show_i (vm, input, cmd, AF_IP6));
921 }
922
923 static clib_error_t *
924 ip4_neighbor_show (vlib_main_t * vm,
925                    unformat_input_t * input, vlib_cli_command_t * cmd)
926 {
927   return (ip_neighbor_show_i (vm, input, cmd, AF_IP4));
928 }
929
930 static clib_error_t *
931 ip6_neighbor_show_sorted (vlib_main_t * vm,
932                           unformat_input_t * input, vlib_cli_command_t * cmd)
933 {
934   return (ip_neighbor_show_sorted_i (vm, input, cmd, AF_IP6));
935 }
936
937 static clib_error_t *
938 ip4_neighbor_show_sorted (vlib_main_t * vm,
939                           unformat_input_t * input, vlib_cli_command_t * cmd)
940 {
941   return (ip_neighbor_show_sorted_i (vm, input, cmd, AF_IP4));
942 }
943
944 /*?
945  * Display all the IP neighbor entries.
946  *
947  * @cliexpar
948  * Example of how to display the IPv4 ARP table:
949  * @cliexstart{show ip neighbor}
950  *    Time      FIB        IP4       Flags      Ethernet              Interface
951  *    346.3028   0       6.1.1.3            de:ad:be:ef:ba:be   GigabitEthernet2/0/0
952  *   3077.4271   0       6.1.1.4       S    de:ad:be:ef:ff:ff   GigabitEthernet2/0/0
953  *   2998.6409   1       6.2.2.3            de:ad:be:ef:00:01   GigabitEthernet2/0/0
954  * Proxy arps enabled for:
955  * Fib_index 0   6.0.0.1 - 6.0.0.11
956  * @cliexend
957  ?*/
958 /* *INDENT-OFF* */
959 VLIB_CLI_COMMAND (show_ip_neighbors_cmd_node, static) = {
960   .path = "show ip neighbors",
961   .function = ip_neighbor_show,
962   .short_help = "show ip neighbors [interface]",
963 };
964 VLIB_CLI_COMMAND (show_ip4_neighbors_cmd_node, static) = {
965   .path = "show ip4 neighbors",
966   .function = ip4_neighbor_show,
967   .short_help = "show ip4 neighbors [interface]",
968 };
969 VLIB_CLI_COMMAND (show_ip6_neighbors_cmd_node, static) = {
970   .path = "show ip6 neighbors",
971   .function = ip6_neighbor_show,
972   .short_help = "show ip6 neighbors [interface]",
973 };
974 VLIB_CLI_COMMAND (show_ip_neighbor_cmd_node, static) = {
975   .path = "show ip neighbor",
976   .function = ip_neighbor_show,
977   .short_help = "show ip neighbor [interface]",
978 };
979 VLIB_CLI_COMMAND (show_ip4_neighbor_cmd_node, static) = {
980   .path = "show ip4 neighbor",
981   .function = ip4_neighbor_show,
982   .short_help = "show ip4 neighbor [interface]",
983 };
984 VLIB_CLI_COMMAND (show_ip6_neighbor_cmd_node, static) = {
985   .path = "show ip6 neighbor",
986   .function = ip6_neighbor_show,
987   .short_help = "show ip6 neighbor [interface]",
988 };
989 VLIB_CLI_COMMAND (show_ip4_neighbor_sorted_cmd_node, static) = {
990   .path = "show ip4 neighbor-sorted",
991   .function = ip4_neighbor_show_sorted,
992   .short_help = "show ip4 neighbor-sorted",
993 };
994 VLIB_CLI_COMMAND (show_ip6_neighbor_sorted_cmd_node, static) = {
995   .path = "show ip6 neighbor-sorted",
996   .function = ip6_neighbor_show_sorted,
997   .short_help = "show ip6 neighbor-sorted",
998 };
999 /* *INDENT-ON* */
1000
1001 static ip_neighbor_vft_t ip_nbr_vfts[N_AF];
1002
1003 void
1004 ip_neighbor_register (ip_address_family_t af, const ip_neighbor_vft_t * vft)
1005 {
1006   ip_nbr_vfts[af] = *vft;
1007 }
1008
1009 void
1010 ip_neighbor_probe_dst (const ip_adjacency_t * adj, const ip46_address_t * dst)
1011 {
1012   if (!vnet_sw_interface_is_admin_up (vnet_get_main (),
1013                                       adj->rewrite_header.sw_if_index))
1014     return;
1015
1016   switch (adj->ia_nh_proto)
1017     {
1018     case FIB_PROTOCOL_IP6:
1019       ip6_neighbor_probe_dst (adj, &dst->ip6);
1020       break;
1021     case FIB_PROTOCOL_IP4:
1022       ip4_neighbor_probe_dst (adj, &dst->ip4);
1023       break;
1024     case FIB_PROTOCOL_MPLS:
1025       ASSERT (0);
1026       break;
1027     }
1028 }
1029
1030 void
1031 ip_neighbor_probe (const ip_adjacency_t * adj)
1032 {
1033   ip_neighbor_probe_dst (adj, &adj->sub_type.nbr.next_hop);
1034 }
1035
1036 void
1037 ip_neighbor_walk (ip_address_family_t af,
1038                   u32 sw_if_index, ip_neighbor_walk_cb_t cb, void *ctx)
1039 {
1040   ip_neighbor_key_t *key;
1041   index_t ipni;
1042
1043   if (~0 == sw_if_index)
1044     {
1045       uword **hash;
1046
1047       vec_foreach (hash, ip_neighbor_db[af].ipndb_hash)
1048       {
1049           /* *INDENT-OFF* */
1050           hash_foreach (key, ipni, *hash,
1051           ({
1052             if (WALK_STOP == cb (ipni, ctx))
1053               break;
1054           }));
1055           /* *INDENT-ON* */
1056       }
1057     }
1058   else
1059     {
1060       uword *hash;
1061
1062       if (vec_len (ip_neighbor_db[af].ipndb_hash) <= sw_if_index)
1063         return;
1064       hash = ip_neighbor_db[af].ipndb_hash[sw_if_index];
1065
1066       /* *INDENT-OFF* */
1067       hash_foreach (key, ipni, hash,
1068       ({
1069         if (WALK_STOP == cb (ipni, ctx))
1070           break;
1071       }));
1072       /* *INDENT-ON* */
1073     }
1074 }
1075
1076 int
1077 ip4_neighbor_proxy_add (u32 fib_index,
1078                         const ip4_address_t * start,
1079                         const ip4_address_t * end)
1080 {
1081   if (ip_nbr_vfts[AF_IP4].inv_proxy4_add)
1082     {
1083       return (ip_nbr_vfts[AF_IP4].inv_proxy4_add (fib_index, start, end));
1084     }
1085
1086   return (-1);
1087 }
1088
1089 int
1090 ip4_neighbor_proxy_delete (u32 fib_index,
1091                            const ip4_address_t * start,
1092                            const ip4_address_t * end)
1093 {
1094   if (ip_nbr_vfts[AF_IP4].inv_proxy4_del)
1095     {
1096       return (ip_nbr_vfts[AF_IP4].inv_proxy4_del (fib_index, start, end));
1097     }
1098   return -1;
1099 }
1100
1101 int
1102 ip4_neighbor_proxy_enable (u32 sw_if_index)
1103 {
1104   if (ip_nbr_vfts[AF_IP4].inv_proxy4_enable)
1105     {
1106       return (ip_nbr_vfts[AF_IP4].inv_proxy4_enable (sw_if_index));
1107     }
1108   return -1;
1109 }
1110
1111 int
1112 ip4_neighbor_proxy_disable (u32 sw_if_index)
1113 {
1114   if (ip_nbr_vfts[AF_IP4].inv_proxy4_disable)
1115     {
1116       return (ip_nbr_vfts[AF_IP4].inv_proxy4_disable (sw_if_index));
1117     }
1118   return -1;
1119 }
1120
1121 int
1122 ip6_neighbor_proxy_add (u32 sw_if_index, const ip6_address_t * addr)
1123 {
1124   if (ip_nbr_vfts[AF_IP6].inv_proxy6_add)
1125     {
1126       return (ip_nbr_vfts[AF_IP6].inv_proxy6_add (sw_if_index, addr));
1127     }
1128   return -1;
1129 }
1130
1131 int
1132 ip6_neighbor_proxy_del (u32 sw_if_index, const ip6_address_t * addr)
1133 {
1134   if (ip_nbr_vfts[AF_IP6].inv_proxy6_del)
1135     {
1136       return (ip_nbr_vfts[AF_IP6].inv_proxy6_del (sw_if_index, addr));
1137     }
1138   return -1;
1139 }
1140
1141 static void
1142 ip_neighbor_ethernet_change_mac (ethernet_main_t * em,
1143                                  u32 sw_if_index, uword opaque)
1144 {
1145   ip_neighbor_t *ipn;
1146   adj_index_t ai;
1147
1148   IP_NEIGHBOR_DBG ("mac-change: %U",
1149                    format_vnet_sw_if_index_name, vnet_get_main (),
1150                    sw_if_index);
1151
1152   /* *INDENT-OFF* */
1153   pool_foreach (ipn, ip_neighbor_pool,
1154   ({
1155     if (ipn->ipn_key->ipnk_sw_if_index == sw_if_index)
1156       adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
1157                        ip_address_family_to_fib_proto(ip_neighbor_get_af(ipn)),
1158                        &ip_addr_46(&ipn->ipn_key->ipnk_ip),
1159                        ip_neighbor_mk_complete_walk,
1160                        ipn);
1161   }));
1162   /* *INDENT-ON* */
1163
1164   ai = adj_glean_get (FIB_PROTOCOL_IP4, sw_if_index);
1165
1166   if (ADJ_INDEX_INVALID != ai)
1167     adj_glean_update_rewrite (ai);
1168 }
1169
1170 void
1171 ip_neighbor_populate (ip_address_family_t af, u32 sw_if_index)
1172 {
1173   index_t *ipnis = NULL, *ipni;
1174   ip_neighbor_t *ipn;
1175
1176   IP_NEIGHBOR_DBG ("populate: %U %U",
1177                    format_vnet_sw_if_index_name, vnet_get_main (),
1178                    sw_if_index, format_ip_address_family, af);
1179
1180   /* *INDENT-OFF* */
1181   pool_foreach (ipn, ip_neighbor_pool,
1182   ({
1183     if (ip_neighbor_get_af(ipn) == af &&
1184         ipn->ipn_key->ipnk_sw_if_index == sw_if_index)
1185       vec_add1 (ipnis, ipn - ip_neighbor_pool);
1186   }));
1187   /* *INDENT-ON* */
1188
1189   vec_foreach (ipni, ipnis)
1190   {
1191     ipn = ip_neighbor_get (*ipni);
1192
1193     adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
1194                      ip_address_family_to_fib_proto (ip_neighbor_get_af
1195                                                      (ipn)),
1196                      &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
1197                      ip_neighbor_mk_complete_walk, ipn);
1198   }
1199   vec_free (ipnis);
1200 }
1201
1202 void
1203 ip_neighbor_flush (ip_address_family_t af, u32 sw_if_index)
1204 {
1205   index_t *ipnis = NULL, *ipni;
1206   ip_neighbor_t *ipn;
1207
1208
1209   IP_NEIGHBOR_DBG ("flush: %U %U",
1210                    format_vnet_sw_if_index_name, vnet_get_main (),
1211                    sw_if_index, format_ip_address_family, af);
1212
1213   /* *INDENT-OFF* */
1214   pool_foreach (ipn, ip_neighbor_pool,
1215   ({
1216     if (ip_neighbor_get_af(ipn) == af &&
1217         ipn->ipn_key->ipnk_sw_if_index == sw_if_index &&
1218         ip_neighbor_is_dynamic (ipn))
1219       vec_add1 (ipnis, ipn - ip_neighbor_pool);
1220   }));
1221   /* *INDENT-ON* */
1222
1223   vec_foreach (ipni, ipnis) ip_neighbor_free (ip_neighbor_get (*ipni));
1224   vec_free (ipnis);
1225 }
1226
1227 static walk_rc_t
1228 ip_neighbor_mark_one (index_t ipni, void *ctx)
1229 {
1230   ip_neighbor_t *ipn;
1231
1232   ipn = ip_neighbor_get (ipni);
1233
1234   ipn->ipn_flags |= IP_NEIGHBOR_FLAG_STALE;
1235
1236   return (WALK_CONTINUE);
1237 }
1238
1239 void
1240 ip_neighbor_mark (ip_address_family_t af)
1241 {
1242   ip_neighbor_walk (af, ~0, ip_neighbor_mark_one, NULL);
1243 }
1244
1245 typedef struct ip_neighbor_sweep_ctx_t_
1246 {
1247   index_t *ipnsc_stale;
1248 } ip_neighbor_sweep_ctx_t;
1249
1250 static walk_rc_t
1251 ip_neighbor_sweep_one (index_t ipni, void *arg)
1252 {
1253   ip_neighbor_sweep_ctx_t *ctx = arg;
1254   ip_neighbor_t *ipn;
1255
1256   ipn = ip_neighbor_get (ipni);
1257
1258   if (ipn->ipn_flags & IP_NEIGHBOR_FLAG_STALE)
1259     {
1260       vec_add1 (ctx->ipnsc_stale, ipni);
1261     }
1262
1263   return (WALK_CONTINUE);
1264 }
1265
1266 void
1267 ip_neighbor_sweep (ip_address_family_t af)
1268 {
1269   ip_neighbor_sweep_ctx_t ctx = { };
1270   index_t *ipni;
1271
1272   ip_neighbor_walk (af, ~0, ip_neighbor_sweep_one, &ctx);
1273
1274   vec_foreach (ipni, ctx.ipnsc_stale)
1275   {
1276     ip_neighbor_free (ip_neighbor_get (*ipni));
1277   }
1278   vec_free (ctx.ipnsc_stale);
1279 }
1280
1281 /*
1282  * Remove any arp entries associated with the specified interface
1283  */
1284 static clib_error_t *
1285 ip_neighbor_interface_admin_change (vnet_main_t * vnm,
1286                                     u32 sw_if_index, u32 flags)
1287 {
1288   ip_address_family_t af;
1289
1290   IP_NEIGHBOR_DBG ("interface-admin: %U  %s",
1291                    format_vnet_sw_if_index_name, vnet_get_main (),
1292                    sw_if_index,
1293                    (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP ? "up" : "down"));
1294
1295   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1296     {
1297       FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_populate (af, sw_if_index);
1298     }
1299   else
1300     {
1301       /* admin down, flush all neighbours */
1302       FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_flush (af, sw_if_index);
1303     }
1304
1305   return (NULL);
1306 }
1307
1308 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip_neighbor_interface_admin_change);
1309
1310 /*
1311  * Remove any arp entries associated with the specified interface
1312  */
1313 static clib_error_t *
1314 ip_neighbor_delete_sw_interface (vnet_main_t * vnm,
1315                                  u32 sw_if_index, u32 is_add)
1316 {
1317   IP_NEIGHBOR_DBG ("interface-change: %U  %s",
1318                    format_vnet_sw_if_index_name, vnet_get_main (),
1319                    sw_if_index, (is_add ? "add" : "del"));
1320
1321   if (!is_add && sw_if_index != ~0)
1322     {
1323       ip_address_family_t af;
1324
1325       FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_flush (af, sw_if_index);
1326     }
1327
1328   return (NULL);
1329 }
1330
1331 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip_neighbor_delete_sw_interface);
1332
1333 typedef struct ip_neighbor_walk_covered_ctx_t_
1334 {
1335   ip_address_t addr;
1336   u32 length;
1337   index_t *ipnis;
1338 } ip_neighbor_walk_covered_ctx_t;
1339
1340 static walk_rc_t
1341 ip_neighbor_walk_covered (index_t ipni, void *arg)
1342 {
1343   ip_neighbor_walk_covered_ctx_t *ctx = arg;
1344   ip_neighbor_t *ipn;
1345
1346   ipn = ip_neighbor_get (ipni);
1347
1348   if (AF_IP4 == ip_addr_version (&ctx->addr))
1349     {
1350       if (ip4_destination_matches_route (&ip4_main,
1351                                          &ip_addr_v4 (&ipn->ipn_key->ipnk_ip),
1352                                          &ip_addr_v4 (&ctx->addr),
1353                                          ctx->length) &&
1354           ip_neighbor_is_dynamic (ipn))
1355         {
1356           vec_add1 (ctx->ipnis, ip_neighbor_get_index (ipn));
1357         }
1358     }
1359   else if (AF_IP6 == ip_addr_version (&ctx->addr))
1360     {
1361       if (ip6_destination_matches_route (&ip6_main,
1362                                          &ip_addr_v6 (&ipn->ipn_key->ipnk_ip),
1363                                          &ip_addr_v6 (&ctx->addr),
1364                                          ctx->length) &&
1365           ip_neighbor_is_dynamic (ipn))
1366         {
1367           vec_add1 (ctx->ipnis, ip_neighbor_get_index (ipn));
1368         }
1369     }
1370   return (WALK_CONTINUE);
1371 }
1372
1373
1374 /*
1375  * callback when an interface address is added or deleted
1376  */
1377 static void
1378 ip_neighbor_add_del_interface_address_v4 (ip4_main_t * im,
1379                                           uword opaque,
1380                                           u32 sw_if_index,
1381                                           ip4_address_t * address,
1382                                           u32 address_length,
1383                                           u32 if_address_index, u32 is_del)
1384 {
1385   /*
1386    * Flush the ARP cache of all entries covered by the address
1387    * that is being removed.
1388    */
1389   IP_NEIGHBOR_DBG ("addr-%d: %U, %U/%d",
1390                    (is_del ? "del" : "add"),
1391                    format_vnet_sw_if_index_name, vnet_get_main (),
1392                    sw_if_index, format_ip4_address, address, address_length);
1393
1394   if (is_del)
1395     {
1396       /* *INDENT-OFF* */
1397       ip_neighbor_walk_covered_ctx_t ctx = {
1398         .addr = {
1399           .ip.ip4 = *address,
1400           .version = AF_IP4,
1401         },
1402         .length = address_length,
1403       };
1404       /* *INDENT-ON* */
1405       index_t *ipni;
1406
1407       ip_neighbor_walk (AF_IP4, sw_if_index, ip_neighbor_walk_covered, &ctx);
1408
1409       vec_foreach (ipni, ctx.ipnis)
1410         ip_neighbor_free (ip_neighbor_get (*ipni));
1411
1412       vec_free (ctx.ipnis);
1413     }
1414 }
1415
1416 /*
1417  * callback when an interface address is added or deleted
1418  */
1419 static void
1420 ip_neighbor_add_del_interface_address_v6 (ip6_main_t * im,
1421                                           uword opaque,
1422                                           u32 sw_if_index,
1423                                           ip6_address_t * address,
1424                                           u32 address_length,
1425                                           u32 if_address_index, u32 is_del)
1426 {
1427   /*
1428    * Flush the ARP cache of all entries covered by the address
1429    * that is being removed.
1430    */
1431   IP_NEIGHBOR_DBG ("addr-change: %U, %U/%d %s",
1432                    format_vnet_sw_if_index_name, vnet_get_main (),
1433                    sw_if_index, format_ip6_address, address, address_length,
1434                    (is_del ? "del" : "add"));
1435
1436   if (is_del)
1437     {
1438       /* *INDENT-OFF* */
1439       ip_neighbor_walk_covered_ctx_t ctx = {
1440         .addr = {
1441           .ip.ip6 = *address,
1442           .version = AF_IP6,
1443         },
1444         .length = address_length,
1445       };
1446       /* *INDENT-ON* */
1447       index_t *ipni;
1448
1449       ip_neighbor_walk (AF_IP6, sw_if_index, ip_neighbor_walk_covered, &ctx);
1450
1451       vec_foreach (ipni, ctx.ipnis)
1452         ip_neighbor_free (ip_neighbor_get (*ipni));
1453
1454       vec_free (ctx.ipnis);
1455     }
1456 }
1457
1458 typedef struct ip_neighbor_table_bind_ctx_t_
1459 {
1460   u32 new_fib_index;
1461   u32 old_fib_index;
1462 } ip_neighbor_table_bind_ctx_t;
1463
1464 static walk_rc_t
1465 ip_neighbor_walk_table_bind (index_t ipni, void *arg)
1466 {
1467   ip_neighbor_table_bind_ctx_t *ctx = arg;
1468   ip_neighbor_t *ipn;
1469
1470   ipn = ip_neighbor_get (ipni);
1471   ip_neighbor_adj_fib_remove (ipn, ctx->old_fib_index);
1472   ip_neighbor_adj_fib_add (ipn, ctx->new_fib_index);
1473
1474   return (WALK_CONTINUE);
1475 }
1476
1477 static void
1478 ip_neighbor_table_bind_v4 (ip4_main_t * im,
1479                            uword opaque,
1480                            u32 sw_if_index,
1481                            u32 new_fib_index, u32 old_fib_index)
1482 {
1483   ip_neighbor_table_bind_ctx_t ctx = {
1484     .old_fib_index = old_fib_index,
1485     .new_fib_index = new_fib_index,
1486   };
1487
1488   ip_neighbor_walk (AF_IP4, sw_if_index, ip_neighbor_walk_table_bind, &ctx);
1489 }
1490
1491 static void
1492 ip_neighbor_table_bind_v6 (ip6_main_t * im,
1493                            uword opaque,
1494                            u32 sw_if_index,
1495                            u32 new_fib_index, u32 old_fib_index)
1496 {
1497   ip_neighbor_table_bind_ctx_t ctx = {
1498     .old_fib_index = old_fib_index,
1499     .new_fib_index = new_fib_index,
1500   };
1501
1502   ip_neighbor_walk (AF_IP6, sw_if_index, ip_neighbor_walk_table_bind, &ctx);
1503 }
1504
1505 typedef enum ip_neighbor_age_state_t_
1506 {
1507   IP_NEIGHBOR_AGE_ALIVE,
1508   IP_NEIGHBOR_AGE_PROBE,
1509   IP_NEIGHBOR_AGE_DEAD,
1510 } ip_neighbor_age_state_t;
1511
1512 #define IP_NEIGHBOR_PROCESS_SLEEP_LONG (0)
1513
1514 static ip_neighbor_age_state_t
1515 ip_neighbour_age_out (index_t ipni, f64 now, f64 * wait)
1516 {
1517   ip_address_family_t af;
1518   ip_neighbor_t *ipn;
1519   u32 ipndb_age;
1520   u32 ttl;
1521
1522   ipn = ip_neighbor_get (ipni);
1523   af = ip_neighbor_get_af (ipn);
1524   ipndb_age = ip_neighbor_db[af].ipndb_age;
1525   ttl = now - ipn->ipn_time_last_updated;
1526   *wait = ipndb_age;
1527
1528   if (ttl > ipndb_age)
1529     {
1530       IP_NEIGHBOR_DBG ("aged: %U @%f - %f > %d",
1531                        format_ip_neighbor, ipni, now,
1532                        ipn->ipn_time_last_updated, ipndb_age);
1533       if (ipn->ipn_n_probes > 2)
1534         {
1535           /* 3 strikes and yea-re out */
1536           IP_NEIGHBOR_DBG ("dead: %U", format_ip_neighbor, ipni);
1537           *wait = 1;
1538           return (IP_NEIGHBOR_AGE_DEAD);
1539         }
1540       else
1541         {
1542           adj_index_t ai;
1543
1544           ai = adj_glean_get (ip_address_family_to_fib_proto (af),
1545                               ip_neighbor_get_sw_if_index (ipn));
1546
1547           if (ADJ_INDEX_INVALID != ai)
1548             ip_neighbor_probe_dst (adj_get (ai),
1549                                    &ip_addr_46 (&ipn->ipn_key->ipnk_ip));
1550
1551           ipn->ipn_n_probes++;
1552           *wait = 1;
1553         }
1554     }
1555   else
1556     {
1557       /* here we are sure that ttl <= ipndb_age */
1558       *wait = ipndb_age - ttl + 1;
1559       return (IP_NEIGHBOR_AGE_ALIVE);
1560     }
1561
1562   return (IP_NEIGHBOR_AGE_PROBE);
1563 }
1564
1565 typedef enum ip_neighbor_process_event_t_
1566 {
1567   IP_NEIGHBOR_AGE_PROCESS_WAKEUP,
1568 } ip_neighbor_process_event_t;
1569
1570 static uword
1571 ip_neighbor_age_loop (vlib_main_t * vm,
1572                       vlib_node_runtime_t * rt,
1573                       vlib_frame_t * f, ip_address_family_t af)
1574 {
1575   uword event_type, *event_data = NULL;
1576   f64 timeout;
1577
1578   /* Set the timeout to an effectively infinite value when the process starts */
1579   timeout = IP_NEIGHBOR_PROCESS_SLEEP_LONG;
1580
1581   while (1)
1582     {
1583       f64 now;
1584
1585       if (!timeout)
1586         vlib_process_wait_for_event (vm);
1587       else
1588         vlib_process_wait_for_event_or_clock (vm, timeout);
1589
1590       event_type = vlib_process_get_events (vm, &event_data);
1591       vec_reset_length (event_data);
1592
1593       now = vlib_time_now (vm);
1594
1595       switch (event_type)
1596         {
1597         case ~0:
1598           {
1599             /* timer expired */
1600             ip_neighbor_elt_t *elt, *head;
1601             f64 wait;
1602
1603             timeout = ip_neighbor_db[af].ipndb_age;
1604             head = pool_elt_at_index (ip_neighbor_elt_pool,
1605                                       ip_neighbor_list_head[af]);
1606
1607           /* *INDENT-OFF*/
1608           /* the list is time sorted, newest first, so start from the back
1609            * and work forwards. Stop when we get to one that is alive */
1610           restart:
1611           clib_llist_foreach_reverse(ip_neighbor_elt_pool,
1612                                      ipne_anchor, head, elt,
1613           ({
1614             ip_neighbor_age_state_t res;
1615
1616             res = ip_neighbour_age_out(elt->ipne_index, now, &wait);
1617
1618             if (IP_NEIGHBOR_AGE_ALIVE == res) {
1619               /* the oldest neighbor has not yet expired, go back to sleep */
1620               timeout = clib_min (wait, timeout);
1621               break;
1622             }
1623             else if (IP_NEIGHBOR_AGE_DEAD == res) {
1624               /* the oldest neighbor is dead, pop it, then restart the walk
1625                * again from the back */
1626               ip_neighbor_free (ip_neighbor_get(elt->ipne_index));
1627               goto restart;
1628             }
1629
1630             timeout = clib_min (wait, timeout);
1631           }));
1632           /* *INDENT-ON* */
1633             break;
1634           }
1635         case IP_NEIGHBOR_AGE_PROCESS_WAKEUP:
1636           {
1637
1638             if (!ip_neighbor_db[af].ipndb_age)
1639               {
1640                 /* aging has been disabled */
1641                 timeout = 0;
1642                 break;
1643               }
1644             ip_neighbor_elt_t *elt, *head;
1645
1646             head = pool_elt_at_index (ip_neighbor_elt_pool,
1647                                       ip_neighbor_list_head[af]);
1648             /* no neighbors yet */
1649             if (clib_llist_is_empty (ip_neighbor_elt_pool, ipne_anchor, head))
1650               {
1651                 timeout = ip_neighbor_db[af].ipndb_age;
1652                 break;
1653               }
1654
1655             /* poke the oldset neighbour for aging, which returns how long we sleep for */
1656             elt = clib_llist_prev (ip_neighbor_elt_pool, ipne_anchor, head);
1657             ip_neighbour_age_out (elt->ipne_index, now, &timeout);
1658             break;
1659           }
1660         }
1661     }
1662   return 0;
1663 }
1664
1665 static uword
1666 ip4_neighbor_age_process (vlib_main_t * vm,
1667                           vlib_node_runtime_t * rt, vlib_frame_t * f)
1668 {
1669   return (ip_neighbor_age_loop (vm, rt, f, AF_IP4));
1670 }
1671
1672 static uword
1673 ip6_neighbor_age_process (vlib_main_t * vm,
1674                           vlib_node_runtime_t * rt, vlib_frame_t * f)
1675 {
1676   return (ip_neighbor_age_loop (vm, rt, f, AF_IP6));
1677 }
1678
1679 /* *INDENT-OFF* */
1680 VLIB_REGISTER_NODE (ip4_neighbor_age_process_node,static) = {
1681   .function = ip4_neighbor_age_process,
1682   .type = VLIB_NODE_TYPE_PROCESS,
1683   .name = "ip4-neighbor-age-process",
1684 };
1685 VLIB_REGISTER_NODE (ip6_neighbor_age_process_node,static) = {
1686   .function = ip6_neighbor_age_process,
1687   .type = VLIB_NODE_TYPE_PROCESS,
1688   .name = "ip6-neighbor-age-process",
1689 };
1690 /* *INDENT-ON* */
1691
1692 int
1693 ip_neighbor_config (ip_address_family_t af, u32 limit, u32 age, bool recycle)
1694 {
1695   ip_neighbor_db[af].ipndb_limit = limit;
1696   ip_neighbor_db[af].ipndb_recycle = recycle;
1697   ip_neighbor_db[af].ipndb_age = age;
1698
1699   vlib_process_signal_event (vlib_get_main (),
1700                              (AF_IP4 == af ?
1701                               ip4_neighbor_age_process_node.index :
1702                               ip6_neighbor_age_process_node.index),
1703                              IP_NEIGHBOR_AGE_PROCESS_WAKEUP, 0);
1704
1705   return (0);
1706 }
1707
1708 static clib_error_t *
1709 ip_neighbor_config_show (vlib_main_t * vm,
1710                          unformat_input_t * input, vlib_cli_command_t * cmd)
1711 {
1712   ip_address_family_t af;
1713
1714   /* *INDENT-OFF* */
1715   FOR_EACH_IP_ADDRESS_FAMILY(af) {
1716     vlib_cli_output (vm, "%U:", format_ip_address_family, af);
1717     vlib_cli_output (vm, "  limit:%d, age:%d, recycle:%d",
1718                      ip_neighbor_db[af].ipndb_limit,
1719                      ip_neighbor_db[af].ipndb_age,
1720                      ip_neighbor_db[af].ipndb_recycle);
1721   }
1722
1723   /* *INDENT-ON* */
1724   return (NULL);
1725 }
1726
1727 /* *INDENT-OFF* */
1728 VLIB_CLI_COMMAND (show_ip_neighbor_cfg_cmd_node, static) = {
1729   .path = "show ip neighbor-config",
1730   .function = ip_neighbor_config_show,
1731   .short_help = "show ip neighbor-config",
1732 };
1733 /* *INDENT-ON* */
1734
1735 static clib_error_t *
1736 ip_neighbor_init (vlib_main_t * vm)
1737 {
1738   {
1739     ip4_add_del_interface_address_callback_t cb = {
1740       .function = ip_neighbor_add_del_interface_address_v4,
1741     };
1742     vec_add1 (ip4_main.add_del_interface_address_callbacks, cb);
1743   }
1744   {
1745     ip6_add_del_interface_address_callback_t cb = {
1746       .function = ip_neighbor_add_del_interface_address_v6,
1747     };
1748     vec_add1 (ip6_main.add_del_interface_address_callbacks, cb);
1749   }
1750   {
1751     ip4_table_bind_callback_t cb = {
1752       .function = ip_neighbor_table_bind_v4,
1753     };
1754     vec_add1 (ip4_main.table_bind_callbacks, cb);
1755   }
1756   {
1757     ip6_table_bind_callback_t cb = {
1758       .function = ip_neighbor_table_bind_v6,
1759     };
1760     vec_add1 (ip6_main.table_bind_callbacks, cb);
1761   }
1762   {
1763     ethernet_address_change_ctx_t ctx = {
1764       .function = ip_neighbor_ethernet_change_mac,
1765       .function_opaque = 0,
1766     };
1767     vec_add1 (ethernet_main.address_change_callbacks, ctx);
1768   }
1769
1770   ipn_logger = vlib_log_register_class ("ip", "neighbor");
1771
1772   ip_address_family_t af;
1773
1774   FOR_EACH_IP_ADDRESS_FAMILY (af)
1775     ip_neighbor_list_head[af] =
1776     clib_llist_make_head (ip_neighbor_elt_pool, ipne_anchor);
1777
1778   return (NULL);
1779 }
1780
1781 /* *INDENT-OFF* */
1782 VLIB_INIT_FUNCTION (ip_neighbor_init) =
1783 {
1784   .runs_after = VLIB_INITS("ip_main_init"),
1785 };
1786 /* *INDENT-ON* */
1787
1788 /*
1789  * fd.io coding-style-patch-verification: ON
1790  *
1791  * Local Variables:
1792  * eval: (c-set-style "gnu")
1793  * End:
1794  */