2 * src/vnet/ip/ip_neighboor.c: ip neighbor generic handling
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <vppinfra/llist.h>
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>
25 #include <vnet/ip/ip6_ll_table.h>
26 #include <vnet/fib/fib_table.h>
27 #include <vnet/adj/adj_mcast.h>
29 /** Pool for All IP neighbors */
30 static ip_neighbor_t *ip_neighbor_pool;
32 /** protocol specific lists of time sorted neighbors */
33 index_t ip_neighbor_list_head[N_AF];
35 typedef struct ip_neighbor_elt_t_
37 clib_llist_anchor_t ipne_anchor;
41 /** Pool of linked list elemeents */
42 ip_neighbor_elt_t *ip_neighbor_elt_pool;
44 typedef struct ip_neighbor_db_t_
46 /** per interface hash */
48 /** per-protocol limit - max number of neighbors*/
50 /** max age of a neighbor before it's forcibly evicted */
52 /** when the limit is reached and new neighbors are created, should
53 * we recycle an old one */
55 /** per-protocol number of elements */
57 /** per-protocol number of elements per-fib-index*/
58 u32 *ipndb_n_elts_per_fib;
61 static vlib_log_class_t ipn_logger;
63 /* DBs of neighbours one per AF */
65 static ip_neighbor_db_t ip_neighbor_db[N_AF] = {
68 /* Default to not aging and not recycling */
70 .ipndb_recycle = false,
74 /* Default to not aging and not recycling */
76 .ipndb_recycle = false,
81 #define IP_NEIGHBOR_DBG(...) \
82 vlib_log_debug (ipn_logger, __VA_ARGS__);
84 #define IP_NEIGHBOR_INFO(...) \
85 vlib_log_notice (ipn_logger, __VA_ARGS__);
88 ip_neighbor_get (index_t ipni)
90 if (pool_is_free_index (ip_neighbor_pool, ipni))
93 return (pool_elt_at_index (ip_neighbor_pool, ipni));
97 ip_neighbor_get_index (const ip_neighbor_t * ipn)
99 return (ipn - ip_neighbor_pool);
103 ip_neighbor_touch (ip_neighbor_t * ipn)
105 ipn->ipn_flags &= ~IP_NEIGHBOR_FLAG_STALE;
109 ip_neighbor_is_dynamic (const ip_neighbor_t * ipn)
111 return (ipn->ipn_flags & IP_NEIGHBOR_FLAG_DYNAMIC);
115 ip_neighbor_get_ip (const ip_neighbor_t * ipn)
117 return (&ipn->ipn_key->ipnk_ip);
121 ip_neighbor_get_af (const ip_neighbor_t * ipn)
123 return (ip_addr_version (&ipn->ipn_key->ipnk_ip));
126 const mac_address_t *
127 ip_neighbor_get_mac (const ip_neighbor_t * ipn)
129 return (&ipn->ipn_mac);
133 ip_neighbor_get_sw_if_index (const ip_neighbor_t * ipn)
135 return (ipn->ipn_key->ipnk_sw_if_index);
139 ip_neighbor_list_remove (ip_neighbor_t * ipn)
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;
145 if (~0 != ipn->ipn_elt)
147 elt = pool_elt_at_index (ip_neighbor_elt_pool, ipn->ipn_elt);
149 clib_llist_remove (ip_neighbor_elt_pool, ipne_anchor, elt);
156 ip_neighbor_refresh (ip_neighbor_t * ipn)
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;
162 ip_neighbor_touch (ipn);
163 ipn->ipn_time_last_updated = vlib_time_now (vlib_get_main ());
164 ipn->ipn_n_probes = 0;
166 if (ip_neighbor_is_dynamic (ipn))
168 if (~0 == ipn->ipn_elt)
169 /* first time insertion */
170 pool_get_zero (ip_neighbor_elt_pool, elt);
173 /* already inserted - extract first */
174 elt = pool_elt_at_index (ip_neighbor_elt_pool, ipn->ipn_elt);
176 clib_llist_remove (ip_neighbor_elt_pool, ipne_anchor, elt);
178 head = pool_elt_at_index (ip_neighbor_elt_pool,
179 ip_neighbor_list_head[ip_neighbor_get_af
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;
189 ip_neighbor_db_add (const ip_neighbor_t * ipn)
191 ip_address_family_t af;
194 af = ip_neighbor_get_af (ipn);
195 sw_if_index = ipn->ipn_key->ipnk_sw_if_index;
197 vec_validate (ip_neighbor_db[af].ipndb_hash, sw_if_index);
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));
203 hash_set_mem (ip_neighbor_db[af].ipndb_hash[sw_if_index],
204 ipn->ipn_key, ip_neighbor_get_index (ipn));
206 ip_neighbor_db[af].ipndb_n_elts++;
210 ip_neighbor_db_remove (const ip_neighbor_t * ipn)
212 ip_address_family_t af;
215 af = ip_neighbor_get_af (ipn);
216 sw_if_index = ipn->ipn_key->ipnk_sw_if_index;
218 vec_validate (ip_neighbor_db[af].ipndb_hash, sw_if_index);
220 hash_unset_mem (ip_neighbor_db[af].ipndb_hash[sw_if_index], ipn->ipn_key);
222 ip_neighbor_db[af].ipndb_n_elts--;
225 static ip_neighbor_t *
226 ip_neighbor_db_find (const ip_neighbor_key_t * key)
228 ip_address_family_t af;
231 af = ip_addr_version (&key->ipnk_ip);
233 if (key->ipnk_sw_if_index >= vec_len (ip_neighbor_db[af].ipndb_hash))
236 p = hash_get_mem (ip_neighbor_db[af].ipndb_hash
237 [key->ipnk_sw_if_index], key);
240 return ip_neighbor_get (p[0]);
246 ip_af_type_pfx_len (ip_address_family_t type)
248 return (type == AF_IP4 ? 32 : 128);
252 ip_neighbor_adj_fib_add (ip_neighbor_t * ipn, u32 fib_index)
254 ip_address_family_t af;
256 af = ip_neighbor_get_af (ipn);
259 ip6_address_is_link_local_unicast (&ip_addr_v6
260 (&ipn->ipn_key->ipnk_ip)))
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,
266 ipn->ipn_fib_entry_index =
267 ip6_ll_table_entry_update (&pfx, FIB_ROUTE_PATH_FLAG_NONE);
271 fib_protocol_t fproto;
273 fproto = ip_address_family_to_fib_proto (af);
276 .fp_len = ip_af_type_pfx_len (af),
278 .fp_addr = ip_addr_46 (&ipn->ipn_key->ipnk_ip),
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),
286 ipn->ipn_key->ipnk_sw_if_index,
287 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
289 vec_validate (ip_neighbor_db[af].ipndb_n_elts_per_fib, fib_index);
291 ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index]++;
293 if (1 == ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index])
294 fib_table_lock (fib_index, fproto, FIB_SOURCE_ADJ);
299 ip_neighbor_adj_fib_remove (ip_neighbor_t * ipn, u32 fib_index)
301 ip_address_family_t af;
303 af = ip_neighbor_get_af (ipn);
305 if (FIB_NODE_INDEX_INVALID != ipn->ipn_fib_entry_index)
308 ip6_address_is_link_local_unicast (&ip_addr_v6
309 (&ipn->ipn_key->ipnk_ip)))
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,
315 ip6_ll_table_entry_delete (&pfx);
319 fib_protocol_t fproto;
321 fproto = ip_address_family_to_fib_proto (af);
324 .fp_len = ip_af_type_pfx_len (af),
326 .fp_addr = ip_addr_46 (&ipn->ipn_key->ipnk_ip),
329 fib_table_entry_path_remove (fib_index,
332 fib_proto_to_dpo (fproto),
334 ipn->ipn_key->ipnk_sw_if_index,
335 ~0, 1, FIB_ROUTE_PATH_FLAG_NONE);
337 ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index]--;
339 if (0 == ip_neighbor_db[af].ipndb_n_elts_per_fib[fib_index])
340 fib_table_unlock (fib_index, fproto, FIB_SOURCE_ADJ);
346 ip_neighbor_mk_complete (adj_index_t ai, ip_neighbor_t * ipn)
348 adj_nbr_update_rewrite (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE,
349 ethernet_build_rewrite (vnet_get_main (),
351 ipn_key->ipnk_sw_if_index,
352 adj_get_link_type (ai),
353 ipn->ipn_mac.bytes));
357 ip_neighbor_mk_incomplete (adj_index_t ai)
359 ip_adjacency_t *adj = adj_get (ai);
361 adj_nbr_update_rewrite (ai,
362 ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
363 ethernet_build_rewrite (vnet_get_main (),
365 rewrite_header.sw_if_index,
367 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
371 ip_neighbor_mk_complete_walk (adj_index_t ai, void *ctx)
373 ip_neighbor_t *ipn = ctx;
375 ip_neighbor_mk_complete (ai, ipn);
377 return (ADJ_WALK_RC_CONTINUE);
381 ip_neighbor_mk_incomplete_walk (adj_index_t ai, void *ctx)
383 ip_neighbor_mk_incomplete (ai);
385 return (ADJ_WALK_RC_CONTINUE);
389 ip_neighbor_destroy (ip_neighbor_t * ipn)
391 ip_address_family_t af;
393 af = ip_neighbor_get_af (ipn);
395 IP_NEIGHBOR_DBG ("free: %U", format_ip_neighbor,
396 ip_neighbor_get_index (ipn));
398 ip_neighbor_publish (ip_neighbor_get_index (ipn),
399 IP_NEIGHBOR_EVENT_REMOVED);
401 adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
402 ip_address_family_to_fib_proto (af),
403 &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
404 ip_neighbor_mk_incomplete_walk, ipn);
405 ip_neighbor_adj_fib_remove
407 fib_table_get_index_for_sw_if_index
408 (ip_address_family_to_fib_proto (af), ipn->ipn_key->ipnk_sw_if_index));
410 ip_neighbor_list_remove (ipn);
411 ip_neighbor_db_remove (ipn);
412 clib_mem_free (ipn->ipn_key);
414 pool_put (ip_neighbor_pool, ipn);
418 ip_neighbor_force_reuse (ip_address_family_t af)
420 if (!ip_neighbor_db[af].ipndb_recycle)
423 /* pluck the oldest entry, which is the one from the end of the list */
424 ip_neighbor_elt_t *elt, *head;
426 head = pool_elt_at_index (ip_neighbor_elt_pool, ip_neighbor_list_head[af]);
428 if (clib_llist_is_empty (ip_neighbor_elt_pool, ipne_anchor, head))
431 elt = clib_llist_prev (ip_neighbor_elt_pool, ipne_anchor, head);
432 ip_neighbor_destroy (ip_neighbor_get (elt->ipne_index));
437 static ip_neighbor_t *
438 ip_neighbor_alloc (const ip_neighbor_key_t * key,
439 const mac_address_t * mac, ip_neighbor_flags_t flags)
441 ip_address_family_t af;
444 af = ip_addr_version (&key->ipnk_ip);
446 if (ip_neighbor_db[af].ipndb_limit &&
447 (ip_neighbor_db[af].ipndb_n_elts >= ip_neighbor_db[af].ipndb_limit))
449 if (!ip_neighbor_force_reuse (af))
453 pool_get_zero (ip_neighbor_pool, ipn);
455 ipn->ipn_key = clib_mem_alloc (sizeof (*ipn->ipn_key));
456 clib_memcpy (ipn->ipn_key, key, sizeof (*ipn->ipn_key));
458 ipn->ipn_fib_entry_index = FIB_NODE_INDEX_INVALID;
459 ipn->ipn_flags = flags;
462 mac_address_copy (&ipn->ipn_mac, mac);
464 ip_neighbor_db_add (ipn);
466 /* create the adj-fib. the entry in the FIB table for the peer's interface */
467 if (!(ipn->ipn_flags & IP_NEIGHBOR_FLAG_NO_FIB_ENTRY))
468 ip_neighbor_adj_fib_add
469 (ipn, fib_table_get_index_for_sw_if_index
470 (ip_address_family_to_fib_proto (af), ipn->ipn_key->ipnk_sw_if_index));
476 ip_neighbor_add (const ip_address_t * ip,
477 const mac_address_t * mac,
479 ip_neighbor_flags_t flags, u32 * stats_index)
481 fib_protocol_t fproto;
484 /* main thread only */
485 ASSERT (0 == vlib_get_thread_index ());
487 fproto = ip_address_family_to_fib_proto (ip_addr_version (ip));
489 const ip_neighbor_key_t key = {
491 .ipnk_sw_if_index = sw_if_index,
494 ipn = ip_neighbor_db_find (&key);
498 IP_NEIGHBOR_DBG ("update: %U, %U",
499 format_vnet_sw_if_index_name, vnet_get_main (),
500 sw_if_index, format_ip_address, ip,
501 format_ip_neighbor_flags, flags, format_mac_address_t,
504 ip_neighbor_touch (ipn);
506 /* Refuse to over-write static neighbor entry. */
507 if (!(flags & IP_NEIGHBOR_FLAG_STATIC) &&
508 (ipn->ipn_flags & IP_NEIGHBOR_FLAG_STATIC))
510 /* if MAC address match, still check to send event */
511 if (0 == mac_address_cmp (&ipn->ipn_mac, mac))
512 goto check_customers;
516 /* A dynamic entry can become static, but not vice-versa.
517 * i.e. since if it was programmed by the CP then it must
518 * be removed by the CP */
519 if ((flags & IP_NEIGHBOR_FLAG_STATIC) &&
520 !(ipn->ipn_flags & IP_NEIGHBOR_FLAG_STATIC))
522 ip_neighbor_list_remove (ipn);
523 ipn->ipn_flags |= IP_NEIGHBOR_FLAG_STATIC;
524 ipn->ipn_flags &= ~IP_NEIGHBOR_FLAG_DYNAMIC;
528 * prevent a DoS attack from the data-plane that
529 * spams us with no-op updates to the MAC address
531 if (0 == mac_address_cmp (&ipn->ipn_mac, mac))
533 ip_neighbor_refresh (ipn);
534 goto check_customers;
537 mac_address_copy (&ipn->ipn_mac, mac);
541 IP_NEIGHBOR_INFO ("add: %U, %U",
542 format_vnet_sw_if_index_name, vnet_get_main (),
543 sw_if_index, format_ip_address, ip,
544 format_ip_neighbor_flags, flags, format_mac_address_t,
547 ipn = ip_neighbor_alloc (&key, mac, flags);
550 return VNET_API_ERROR_LIMIT_EXCEEDED;
553 /* Update time stamp and flags. */
554 ip_neighbor_refresh (ipn);
556 adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
557 fproto, &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
558 ip_neighbor_mk_complete_walk, ipn);
561 /* Customer(s) requesting event for this address? */
562 ip_neighbor_publish (ip_neighbor_get_index (ipn), IP_NEIGHBOR_EVENT_ADDED);
565 *stats_index = adj_nbr_find (fproto,
566 fib_proto_to_link (fproto),
567 &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
568 ipn->ipn_key->ipnk_sw_if_index);
573 ip_neighbor_del (const ip_address_t * ip, u32 sw_if_index)
577 /* main thread only */
578 ASSERT (0 == vlib_get_thread_index ());
580 IP_NEIGHBOR_INFO ("delete: %U, %U",
581 format_vnet_sw_if_index_name, vnet_get_main (),
582 sw_if_index, format_ip_address, ip);
584 const ip_neighbor_key_t key = {
586 .ipnk_sw_if_index = sw_if_index,
589 ipn = ip_neighbor_db_find (&key);
592 return (VNET_API_ERROR_NO_SUCH_ENTRY);
594 ip_neighbor_destroy (ipn);
599 typedef struct ip_neighbor_del_all_ctx_t_
602 } ip_neighbor_del_all_ctx_t;
605 ip_neighbor_del_all_walk_cb (index_t ipni, void *arg)
607 ip_neighbor_del_all_ctx_t *ctx = arg;
609 vec_add1 (ctx->ipn_del, ipni);
611 return (WALK_CONTINUE);
615 ip_neighbor_del_all (ip_address_family_t af, u32 sw_if_index)
617 IP_NEIGHBOR_INFO ("delete-all: %U, %U",
618 format_ip_address_family, af,
619 format_vnet_sw_if_index_name, vnet_get_main (),
622 ip_neighbor_del_all_ctx_t ctx = {
627 ip_neighbor_walk (af, sw_if_index, ip_neighbor_del_all_walk_cb, &ctx);
630 ctx.ipn_del) ip_neighbor_destroy (ip_neighbor_get (*ipni));
631 vec_free (ctx.ipn_del);
635 ip_neighbor_update (vnet_main_t * vnm, adj_index_t ai)
642 ip_neighbor_key_t key = {
643 .ipnk_sw_if_index = adj->rewrite_header.sw_if_index,
646 ip_address_from_46 (&adj->sub_type.nbr.next_hop,
647 adj->ia_nh_proto, &key.ipnk_ip);
649 ipn = ip_neighbor_db_find (&key);
651 switch (adj->lookup_next_index)
653 case IP_LOOKUP_NEXT_ARP:
656 adj_nbr_walk_nh (adj->rewrite_header.sw_if_index,
658 &adj->sub_type.nbr.next_hop,
659 ip_neighbor_mk_complete_walk, ipn);
664 * no matching ARP entry.
665 * construct the rewrite required to for an ARP packet, and stick
666 * that in the adj's pipe to smoke.
668 adj_nbr_update_rewrite
670 ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
671 ethernet_build_rewrite
673 adj->rewrite_header.sw_if_index,
675 VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
678 * since the FIB has added this adj for a route, it makes sense it
679 * may want to forward traffic sometime soon. Let's send a
680 * speculative ARP. just one. If we were to do periodically that
681 * wouldn't be bad either, but that's more code than i'm prepared to
682 * write at this time for relatively little reward.
685 * adj_nbr_update_rewrite may actually call fib_walk_sync.
686 * fib_walk_sync may allocate a new adjacency and potentially cause
687 * a realloc for adj_pool. When that happens, adj pointer is no
688 * longer valid here.x We refresh adj pointer accordingly.
691 ip_neighbor_probe (adj);
694 case IP_LOOKUP_NEXT_GLEAN:
695 case IP_LOOKUP_NEXT_BCAST:
696 case IP_LOOKUP_NEXT_MCAST:
697 case IP_LOOKUP_NEXT_DROP:
698 case IP_LOOKUP_NEXT_PUNT:
699 case IP_LOOKUP_NEXT_LOCAL:
700 case IP_LOOKUP_NEXT_REWRITE:
701 case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
702 case IP_LOOKUP_NEXT_MIDCHAIN:
703 case IP_LOOKUP_NEXT_ICMP_ERROR:
704 case IP_LOOKUP_N_NEXT:
711 ip_neighbor_learn (const ip_neighbor_learn_t * l)
713 ip_neighbor_add (&l->ip, &l->mac, l->sw_if_index,
714 IP_NEIGHBOR_FLAG_DYNAMIC, NULL);
717 static clib_error_t *
718 ip_neighbor_cmd (vlib_main_t * vm,
719 unformat_input_t * input, vlib_cli_command_t * cmd)
721 ip_address_t ip = IP_ADDRESS_V6_ALL_0S;
722 mac_address_t mac = ZERO_MAC_ADDRESS;
723 vnet_main_t *vnm = vnet_get_main ();
724 ip_neighbor_flags_t flags;
725 u32 sw_if_index = ~0;
729 flags = IP_NEIGHBOR_FLAG_DYNAMIC;
731 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
733 /* set ip arp TenGigE1/1/0/1 1.2.3.4 aa:bb:... or aabb.ccdd... */
734 if (unformat (input, "%U %U %U",
735 unformat_vnet_sw_interface, vnm, &sw_if_index,
736 unformat_ip_address, &ip, unformat_mac_address_t, &mac))
738 else if (unformat (input, "delete") || unformat (input, "del"))
740 else if (unformat (input, "static"))
742 flags |= IP_NEIGHBOR_FLAG_STATIC;
743 flags &= ~IP_NEIGHBOR_FLAG_DYNAMIC;
745 else if (unformat (input, "no-fib-entry"))
746 flags |= IP_NEIGHBOR_FLAG_NO_FIB_ENTRY;
747 else if (unformat (input, "count %d", &count))
753 if (sw_if_index == ~0 ||
754 ip_address_is_zero (&ip) || mac_address_is_zero (&mac))
755 return clib_error_return (0,
756 "specify interface, IP address and MAC: `%U'",
757 format_unformat_error, input);
762 ip_neighbor_add (&ip, &mac, sw_if_index, flags, NULL);
764 ip_neighbor_del (&ip, sw_if_index);
766 ip_address_increment (&ip);
767 mac_address_increment (&mac);
777 * Add or delete IPv4 ARP cache entries.
779 * @note 'set ip neighbor' options (e.g. delete, static, 'fib-id <id>',
780 * 'count <number>', 'interface ip4_addr mac_addr') can be added in
781 * any order and combination.
785 * Add or delete IPv4 ARP cache entries as follows. MAC Address can be in
786 * either aa:bb:cc:dd:ee:ff format or aabb.ccdd.eeff format.
787 * @cliexcmd{set ip neighbor GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
788 * @cliexcmd{set ip neighbor delete GigabitEthernet2/0/0 6.0.0.3 de:ad:be:ef:ba:be}
790 * To add or delete an IPv4 ARP cache entry to or from a specific fib
792 * @cliexcmd{set ip neighbor fib-id 1 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
793 * @cliexcmd{set ip neighbor fib-id 1 delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
795 * Add or delete IPv4 static ARP cache entries as follows:
796 * @cliexcmd{set ip neighbor static GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
797 * @cliexcmd{set ip neighbor static delete GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
799 * For testing / debugging purposes, the 'set ip neighbor' command can add or
800 * delete multiple entries. Supply the 'count N' parameter:
801 * @cliexcmd{set ip neighbor count 10 GigabitEthernet2/0/0 6.0.0.3 dead.beef.babe}
804 VLIB_CLI_COMMAND (ip_neighbor_command, static) = {
805 .path = "set ip neighbor",
807 "set ip neighbor [del] <intfc> <ip-address> <mac-address> [static] [no-fib-entry] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
808 .function = ip_neighbor_cmd,
810 VLIB_CLI_COMMAND (ip_neighbor_command2, static) = {
811 .path = "ip neighbor",
813 "ip neighbor [del] <intfc> <ip-address> <mac-address> [static] [no-fib-entry] [count <count>] [fib-id <fib-id>] [proxy <lo-addr> - <hi-addr>]",
814 .function = ip_neighbor_cmd,
819 ip_neighbor_sort (void *a1, void *a2)
821 index_t *ipni1 = a1, *ipni2 = a2;
822 ip_neighbor_t *ipn1, *ipn2;
825 ipn1 = ip_neighbor_get (*ipni1);
826 ipn2 = ip_neighbor_get (*ipni2);
828 cmp = vnet_sw_interface_compare (vnet_get_main (),
829 ipn1->ipn_key->ipnk_sw_if_index,
830 ipn2->ipn_key->ipnk_sw_if_index);
832 cmp = ip_address_cmp (&ipn1->ipn_key->ipnk_ip, &ipn2->ipn_key->ipnk_ip);
837 ip_neighbor_entries (u32 sw_if_index, ip_address_family_t af)
839 index_t *ipnis = NULL;
843 pool_foreach (ipn, ip_neighbor_pool,
845 if ((sw_if_index == ~0 ||
846 ipn->ipn_key->ipnk_sw_if_index == sw_if_index) &&
848 ip_neighbor_get_af(ipn) == af))
849 vec_add1 (ipnis, ip_neighbor_get_index(ipn));
855 vec_sort_with_function (ipnis, ip_neighbor_sort);
859 static clib_error_t *
860 ip_neighbor_show_sorted_i (vlib_main_t * vm,
861 unformat_input_t * input,
862 vlib_cli_command_t * cmd, ip_address_family_t af)
864 ip_neighbor_elt_t *elt, *head;
866 head = pool_elt_at_index (ip_neighbor_elt_pool, ip_neighbor_list_head[af]);
869 vlib_cli_output (vm, "%=12s%=40s%=6s%=20s%=24s", "Time", "IP",
870 "Flags", "Ethernet", "Interface");
873 /* the list is time sorted, newest first, so start from the back
874 * and work forwards. Stop when we get to one that is alive */
875 clib_llist_foreach_reverse(ip_neighbor_elt_pool,
876 ipne_anchor, head, elt,
878 vlib_cli_output (vm, "%U", format_ip_neighbor, elt->ipne_index);
885 static clib_error_t *
886 ip_neighbor_show_i (vlib_main_t * vm,
887 unformat_input_t * input,
888 vlib_cli_command_t * cmd, ip_address_family_t af)
890 index_t *ipni, *ipnis = NULL;
893 /* Filter entries by interface if given. */
895 (void) unformat_user (input, unformat_vnet_sw_interface, vnet_get_main (),
898 ipnis = ip_neighbor_entries (sw_if_index, af);
901 vlib_cli_output (vm, "%=12s%=40s%=6s%=20s%=24s", "Time", "IP",
902 "Flags", "Ethernet", "Interface");
904 vec_foreach (ipni, ipnis)
906 vlib_cli_output (vm, "%U", format_ip_neighbor, *ipni);
913 static clib_error_t *
914 ip_neighbor_show (vlib_main_t * vm,
915 unformat_input_t * input, vlib_cli_command_t * cmd)
917 return (ip_neighbor_show_i (vm, input, cmd, N_AF));
920 static clib_error_t *
921 ip6_neighbor_show (vlib_main_t * vm,
922 unformat_input_t * input, vlib_cli_command_t * cmd)
924 return (ip_neighbor_show_i (vm, input, cmd, AF_IP6));
927 static clib_error_t *
928 ip4_neighbor_show (vlib_main_t * vm,
929 unformat_input_t * input, vlib_cli_command_t * cmd)
931 return (ip_neighbor_show_i (vm, input, cmd, AF_IP4));
934 static clib_error_t *
935 ip6_neighbor_show_sorted (vlib_main_t * vm,
936 unformat_input_t * input, vlib_cli_command_t * cmd)
938 return (ip_neighbor_show_sorted_i (vm, input, cmd, AF_IP6));
941 static clib_error_t *
942 ip4_neighbor_show_sorted (vlib_main_t * vm,
943 unformat_input_t * input, vlib_cli_command_t * cmd)
945 return (ip_neighbor_show_sorted_i (vm, input, cmd, AF_IP4));
949 * Display all the IP neighbor entries.
952 * Example of how to display the IPv4 ARP table:
953 * @cliexstart{show ip neighbor}
954 * Time FIB IP4 Flags Ethernet Interface
955 * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
956 * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
957 * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
958 * Proxy arps enabled for:
959 * Fib_index 0 6.0.0.1 - 6.0.0.11
963 VLIB_CLI_COMMAND (show_ip_neighbors_cmd_node, static) = {
964 .path = "show ip neighbors",
965 .function = ip_neighbor_show,
966 .short_help = "show ip neighbors [interface]",
968 VLIB_CLI_COMMAND (show_ip4_neighbors_cmd_node, static) = {
969 .path = "show ip4 neighbors",
970 .function = ip4_neighbor_show,
971 .short_help = "show ip4 neighbors [interface]",
973 VLIB_CLI_COMMAND (show_ip6_neighbors_cmd_node, static) = {
974 .path = "show ip6 neighbors",
975 .function = ip6_neighbor_show,
976 .short_help = "show ip6 neighbors [interface]",
978 VLIB_CLI_COMMAND (show_ip_neighbor_cmd_node, static) = {
979 .path = "show ip neighbor",
980 .function = ip_neighbor_show,
981 .short_help = "show ip neighbor [interface]",
983 VLIB_CLI_COMMAND (show_ip4_neighbor_cmd_node, static) = {
984 .path = "show ip4 neighbor",
985 .function = ip4_neighbor_show,
986 .short_help = "show ip4 neighbor [interface]",
988 VLIB_CLI_COMMAND (show_ip6_neighbor_cmd_node, static) = {
989 .path = "show ip6 neighbor",
990 .function = ip6_neighbor_show,
991 .short_help = "show ip6 neighbor [interface]",
993 VLIB_CLI_COMMAND (show_ip4_neighbor_sorted_cmd_node, static) = {
994 .path = "show ip4 neighbor-sorted",
995 .function = ip4_neighbor_show_sorted,
996 .short_help = "show ip4 neighbor-sorted",
998 VLIB_CLI_COMMAND (show_ip6_neighbor_sorted_cmd_node, static) = {
999 .path = "show ip6 neighbor-sorted",
1000 .function = ip6_neighbor_show_sorted,
1001 .short_help = "show ip6 neighbor-sorted",
1005 static ip_neighbor_vft_t ip_nbr_vfts[N_AF];
1008 ip_neighbor_register (ip_address_family_t af, const ip_neighbor_vft_t * vft)
1010 ip_nbr_vfts[af] = *vft;
1014 ip_neighbor_probe_dst (const ip_adjacency_t * adj, const ip46_address_t * dst)
1016 if (!vnet_sw_interface_is_admin_up (vnet_get_main (),
1017 adj->rewrite_header.sw_if_index))
1020 switch (adj->ia_nh_proto)
1022 case FIB_PROTOCOL_IP6:
1023 ip6_neighbor_probe_dst (adj, &dst->ip6);
1025 case FIB_PROTOCOL_IP4:
1026 ip4_neighbor_probe_dst (adj, &dst->ip4);
1028 case FIB_PROTOCOL_MPLS:
1035 ip_neighbor_probe (const ip_adjacency_t * adj)
1037 ip_neighbor_probe_dst (adj, &adj->sub_type.nbr.next_hop);
1041 ip_neighbor_walk (ip_address_family_t af,
1042 u32 sw_if_index, ip_neighbor_walk_cb_t cb, void *ctx)
1044 ip_neighbor_key_t *key;
1047 if (~0 == sw_if_index)
1051 vec_foreach (hash, ip_neighbor_db[af].ipndb_hash)
1054 hash_foreach (key, ipni, *hash,
1056 if (WALK_STOP == cb (ipni, ctx))
1066 if (vec_len (ip_neighbor_db[af].ipndb_hash) <= sw_if_index)
1068 hash = ip_neighbor_db[af].ipndb_hash[sw_if_index];
1071 hash_foreach (key, ipni, hash,
1073 if (WALK_STOP == cb (ipni, ctx))
1081 ip4_neighbor_proxy_add (u32 fib_index,
1082 const ip4_address_t * start,
1083 const ip4_address_t * end)
1085 if (ip_nbr_vfts[AF_IP4].inv_proxy4_add)
1087 return (ip_nbr_vfts[AF_IP4].inv_proxy4_add (fib_index, start, end));
1094 ip4_neighbor_proxy_delete (u32 fib_index,
1095 const ip4_address_t * start,
1096 const ip4_address_t * end)
1098 if (ip_nbr_vfts[AF_IP4].inv_proxy4_del)
1100 return (ip_nbr_vfts[AF_IP4].inv_proxy4_del (fib_index, start, end));
1106 ip4_neighbor_proxy_enable (u32 sw_if_index)
1108 if (ip_nbr_vfts[AF_IP4].inv_proxy4_enable)
1110 return (ip_nbr_vfts[AF_IP4].inv_proxy4_enable (sw_if_index));
1116 ip4_neighbor_proxy_disable (u32 sw_if_index)
1118 if (ip_nbr_vfts[AF_IP4].inv_proxy4_disable)
1120 return (ip_nbr_vfts[AF_IP4].inv_proxy4_disable (sw_if_index));
1126 ip6_neighbor_proxy_add (u32 sw_if_index, const ip6_address_t * addr)
1128 if (ip_nbr_vfts[AF_IP6].inv_proxy6_add)
1130 return (ip_nbr_vfts[AF_IP6].inv_proxy6_add (sw_if_index, addr));
1136 ip6_neighbor_proxy_del (u32 sw_if_index, const ip6_address_t * addr)
1138 if (ip_nbr_vfts[AF_IP6].inv_proxy6_del)
1140 return (ip_nbr_vfts[AF_IP6].inv_proxy6_del (sw_if_index, addr));
1146 ip_neighbor_ethernet_change_mac (ethernet_main_t * em,
1147 u32 sw_if_index, uword opaque)
1152 IP_NEIGHBOR_DBG ("mac-change: %U",
1153 format_vnet_sw_if_index_name, vnet_get_main (),
1157 pool_foreach (ipn, ip_neighbor_pool,
1159 if (ipn->ipn_key->ipnk_sw_if_index == sw_if_index)
1160 adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
1161 ip_address_family_to_fib_proto(ip_neighbor_get_af(ipn)),
1162 &ip_addr_46(&ipn->ipn_key->ipnk_ip),
1163 ip_neighbor_mk_complete_walk,
1168 ai = adj_glean_get (FIB_PROTOCOL_IP4, sw_if_index);
1170 if (ADJ_INDEX_INVALID != ai)
1171 adj_glean_update_rewrite (ai);
1175 ip_neighbor_populate (ip_address_family_t af, u32 sw_if_index)
1177 index_t *ipnis = NULL, *ipni;
1180 IP_NEIGHBOR_DBG ("populate: %U %U",
1181 format_vnet_sw_if_index_name, vnet_get_main (),
1182 sw_if_index, format_ip_address_family, af);
1185 pool_foreach (ipn, ip_neighbor_pool,
1187 if (ip_neighbor_get_af(ipn) == af &&
1188 ipn->ipn_key->ipnk_sw_if_index == sw_if_index)
1189 vec_add1 (ipnis, ipn - ip_neighbor_pool);
1193 vec_foreach (ipni, ipnis)
1195 ipn = ip_neighbor_get (*ipni);
1197 adj_nbr_walk_nh (ipn->ipn_key->ipnk_sw_if_index,
1198 ip_address_family_to_fib_proto (ip_neighbor_get_af
1200 &ip_addr_46 (&ipn->ipn_key->ipnk_ip),
1201 ip_neighbor_mk_complete_walk, ipn);
1207 ip_neighbor_flush (ip_address_family_t af, u32 sw_if_index)
1209 index_t *ipnis = NULL, *ipni;
1213 IP_NEIGHBOR_DBG ("flush: %U %U",
1214 format_vnet_sw_if_index_name, vnet_get_main (),
1215 sw_if_index, format_ip_address_family, af);
1218 pool_foreach (ipn, ip_neighbor_pool,
1220 if (ip_neighbor_get_af(ipn) == af &&
1221 ipn->ipn_key->ipnk_sw_if_index == sw_if_index &&
1222 ip_neighbor_is_dynamic (ipn))
1223 vec_add1 (ipnis, ipn - ip_neighbor_pool);
1227 vec_foreach (ipni, ipnis) ip_neighbor_destroy (ip_neighbor_get (*ipni));
1232 ip_neighbor_mark_one (index_t ipni, void *ctx)
1236 ipn = ip_neighbor_get (ipni);
1238 ipn->ipn_flags |= IP_NEIGHBOR_FLAG_STALE;
1240 return (WALK_CONTINUE);
1244 ip_neighbor_mark (ip_address_family_t af)
1246 ip_neighbor_walk (af, ~0, ip_neighbor_mark_one, NULL);
1249 typedef struct ip_neighbor_sweep_ctx_t_
1251 index_t *ipnsc_stale;
1252 } ip_neighbor_sweep_ctx_t;
1255 ip_neighbor_sweep_one (index_t ipni, void *arg)
1257 ip_neighbor_sweep_ctx_t *ctx = arg;
1260 ipn = ip_neighbor_get (ipni);
1262 if (ipn->ipn_flags & IP_NEIGHBOR_FLAG_STALE)
1264 vec_add1 (ctx->ipnsc_stale, ipni);
1267 return (WALK_CONTINUE);
1271 ip_neighbor_sweep (ip_address_family_t af)
1273 ip_neighbor_sweep_ctx_t ctx = { };
1276 ip_neighbor_walk (af, ~0, ip_neighbor_sweep_one, &ctx);
1278 vec_foreach (ipni, ctx.ipnsc_stale)
1280 ip_neighbor_destroy (ip_neighbor_get (*ipni));
1282 vec_free (ctx.ipnsc_stale);
1286 * Remove any arp entries associated with the specified interface
1288 static clib_error_t *
1289 ip_neighbor_interface_admin_change (vnet_main_t * vnm,
1290 u32 sw_if_index, u32 flags)
1292 ip_address_family_t af;
1294 IP_NEIGHBOR_DBG ("interface-admin: %U %s",
1295 format_vnet_sw_if_index_name, vnet_get_main (),
1297 (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP ? "up" : "down"));
1299 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1301 FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_populate (af, sw_if_index);
1305 /* admin down, flush all neighbours */
1306 FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_flush (af, sw_if_index);
1312 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip_neighbor_interface_admin_change);
1315 * Remove any arp entries associated with the specified interface
1317 static clib_error_t *
1318 ip_neighbor_delete_sw_interface (vnet_main_t * vnm,
1319 u32 sw_if_index, u32 is_add)
1321 IP_NEIGHBOR_DBG ("interface-change: %U %s",
1322 format_vnet_sw_if_index_name, vnet_get_main (),
1323 sw_if_index, (is_add ? "add" : "del"));
1325 if (!is_add && sw_if_index != ~0)
1327 ip_address_family_t af;
1329 FOR_EACH_IP_ADDRESS_FAMILY (af) ip_neighbor_flush (af, sw_if_index);
1335 VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip_neighbor_delete_sw_interface);
1337 typedef struct ip_neighbor_walk_covered_ctx_t_
1342 } ip_neighbor_walk_covered_ctx_t;
1345 ip_neighbor_walk_covered (index_t ipni, void *arg)
1347 ip_neighbor_walk_covered_ctx_t *ctx = arg;
1350 ipn = ip_neighbor_get (ipni);
1352 if (AF_IP4 == ip_addr_version (&ctx->addr))
1354 if (ip4_destination_matches_route (&ip4_main,
1355 &ip_addr_v4 (&ipn->ipn_key->ipnk_ip),
1356 &ip_addr_v4 (&ctx->addr),
1358 ip_neighbor_is_dynamic (ipn))
1360 vec_add1 (ctx->ipnis, ip_neighbor_get_index (ipn));
1363 else if (AF_IP6 == ip_addr_version (&ctx->addr))
1365 if (ip6_destination_matches_route (&ip6_main,
1366 &ip_addr_v6 (&ipn->ipn_key->ipnk_ip),
1367 &ip_addr_v6 (&ctx->addr),
1369 ip_neighbor_is_dynamic (ipn))
1371 vec_add1 (ctx->ipnis, ip_neighbor_get_index (ipn));
1374 return (WALK_CONTINUE);
1379 * callback when an interface address is added or deleted
1382 ip_neighbor_add_del_interface_address_v4 (ip4_main_t * im,
1385 ip4_address_t * address,
1387 u32 if_address_index, u32 is_del)
1390 * Flush the ARP cache of all entries covered by the address
1391 * that is being removed.
1393 IP_NEIGHBOR_DBG ("addr-%d: %U, %U/%d",
1394 (is_del ? "del" : "add"),
1395 format_vnet_sw_if_index_name, vnet_get_main (),
1396 sw_if_index, format_ip4_address, address, address_length);
1401 ip_neighbor_walk_covered_ctx_t ctx = {
1406 .length = address_length,
1411 ip_neighbor_walk (AF_IP4, sw_if_index, ip_neighbor_walk_covered, &ctx);
1413 vec_foreach (ipni, ctx.ipnis)
1414 ip_neighbor_destroy (ip_neighbor_get (*ipni));
1416 vec_free (ctx.ipnis);
1421 * callback when an interface address is added or deleted
1424 ip_neighbor_add_del_interface_address_v6 (ip6_main_t * im,
1427 ip6_address_t * address,
1429 u32 if_address_index, u32 is_del)
1432 * Flush the ARP cache of all entries covered by the address
1433 * that is being removed.
1435 IP_NEIGHBOR_DBG ("addr-change: %U, %U/%d %s",
1436 format_vnet_sw_if_index_name, vnet_get_main (),
1437 sw_if_index, format_ip6_address, address, address_length,
1438 (is_del ? "del" : "add"));
1443 ip_neighbor_walk_covered_ctx_t ctx = {
1448 .length = address_length,
1453 ip_neighbor_walk (AF_IP6, sw_if_index, ip_neighbor_walk_covered, &ctx);
1455 vec_foreach (ipni, ctx.ipnis)
1456 ip_neighbor_destroy (ip_neighbor_get (*ipni));
1458 vec_free (ctx.ipnis);
1462 typedef struct ip_neighbor_table_bind_ctx_t_
1466 } ip_neighbor_table_bind_ctx_t;
1469 ip_neighbor_walk_table_bind (index_t ipni, void *arg)
1471 ip_neighbor_table_bind_ctx_t *ctx = arg;
1474 ipn = ip_neighbor_get (ipni);
1475 ip_neighbor_adj_fib_remove (ipn, ctx->old_fib_index);
1476 ip_neighbor_adj_fib_add (ipn, ctx->new_fib_index);
1478 return (WALK_CONTINUE);
1482 ip_neighbor_table_bind_v4 (ip4_main_t * im,
1485 u32 new_fib_index, u32 old_fib_index)
1487 ip_neighbor_table_bind_ctx_t ctx = {
1488 .old_fib_index = old_fib_index,
1489 .new_fib_index = new_fib_index,
1492 ip_neighbor_walk (AF_IP4, sw_if_index, ip_neighbor_walk_table_bind, &ctx);
1496 ip_neighbor_table_bind_v6 (ip6_main_t * im,
1499 u32 new_fib_index, u32 old_fib_index)
1501 ip_neighbor_table_bind_ctx_t ctx = {
1502 .old_fib_index = old_fib_index,
1503 .new_fib_index = new_fib_index,
1506 ip_neighbor_walk (AF_IP6, sw_if_index, ip_neighbor_walk_table_bind, &ctx);
1509 typedef enum ip_neighbor_age_state_t_
1511 IP_NEIGHBOR_AGE_ALIVE,
1512 IP_NEIGHBOR_AGE_PROBE,
1513 IP_NEIGHBOR_AGE_DEAD,
1514 } ip_neighbor_age_state_t;
1516 #define IP_NEIGHBOR_PROCESS_SLEEP_LONG (0)
1518 static ip_neighbor_age_state_t
1519 ip_neighbour_age_out (index_t ipni, f64 now, f64 * wait)
1521 ip_address_family_t af;
1526 ipn = ip_neighbor_get (ipni);
1527 af = ip_neighbor_get_af (ipn);
1528 ipndb_age = ip_neighbor_db[af].ipndb_age;
1529 ttl = now - ipn->ipn_time_last_updated;
1532 if (ttl > ipndb_age)
1534 IP_NEIGHBOR_DBG ("aged: %U @%f - %f > %d",
1535 format_ip_neighbor, ipni, now,
1536 ipn->ipn_time_last_updated, ipndb_age);
1537 if (ipn->ipn_n_probes > 2)
1539 /* 3 strikes and yea-re out */
1540 IP_NEIGHBOR_DBG ("dead: %U", format_ip_neighbor, ipni);
1542 return (IP_NEIGHBOR_AGE_DEAD);
1548 ai = adj_glean_get (ip_address_family_to_fib_proto (af),
1549 ip_neighbor_get_sw_if_index (ipn));
1551 if (ADJ_INDEX_INVALID != ai)
1552 ip_neighbor_probe_dst (adj_get (ai),
1553 &ip_addr_46 (&ipn->ipn_key->ipnk_ip));
1555 ipn->ipn_n_probes++;
1561 /* here we are sure that ttl <= ipndb_age */
1562 *wait = ipndb_age - ttl + 1;
1563 return (IP_NEIGHBOR_AGE_ALIVE);
1566 return (IP_NEIGHBOR_AGE_PROBE);
1569 typedef enum ip_neighbor_process_event_t_
1571 IP_NEIGHBOR_AGE_PROCESS_WAKEUP,
1572 } ip_neighbor_process_event_t;
1575 ip_neighbor_age_loop (vlib_main_t * vm,
1576 vlib_node_runtime_t * rt,
1577 vlib_frame_t * f, ip_address_family_t af)
1579 uword event_type, *event_data = NULL;
1582 /* Set the timeout to an effectively infinite value when the process starts */
1583 timeout = IP_NEIGHBOR_PROCESS_SLEEP_LONG;
1590 vlib_process_wait_for_event (vm);
1592 vlib_process_wait_for_event_or_clock (vm, timeout);
1594 event_type = vlib_process_get_events (vm, &event_data);
1595 vec_reset_length (event_data);
1597 now = vlib_time_now (vm);
1604 ip_neighbor_elt_t *elt, *head;
1607 timeout = ip_neighbor_db[af].ipndb_age;
1608 head = pool_elt_at_index (ip_neighbor_elt_pool,
1609 ip_neighbor_list_head[af]);
1612 /* the list is time sorted, newest first, so start from the back
1613 * and work forwards. Stop when we get to one that is alive */
1615 clib_llist_foreach_reverse(ip_neighbor_elt_pool,
1616 ipne_anchor, head, elt,
1618 ip_neighbor_age_state_t res;
1620 res = ip_neighbour_age_out(elt->ipne_index, now, &wait);
1622 if (IP_NEIGHBOR_AGE_ALIVE == res) {
1623 /* the oldest neighbor has not yet expired, go back to sleep */
1624 timeout = clib_min (wait, timeout);
1627 else if (IP_NEIGHBOR_AGE_DEAD == res) {
1628 /* the oldest neighbor is dead, pop it, then restart the walk
1629 * again from the back */
1630 ip_neighbor_destroy (ip_neighbor_get(elt->ipne_index));
1634 timeout = clib_min (wait, timeout);
1639 case IP_NEIGHBOR_AGE_PROCESS_WAKEUP:
1642 if (!ip_neighbor_db[af].ipndb_age)
1644 /* aging has been disabled */
1648 ip_neighbor_elt_t *elt, *head;
1650 head = pool_elt_at_index (ip_neighbor_elt_pool,
1651 ip_neighbor_list_head[af]);
1652 /* no neighbors yet */
1653 if (clib_llist_is_empty (ip_neighbor_elt_pool, ipne_anchor, head))
1655 timeout = ip_neighbor_db[af].ipndb_age;
1659 /* poke the oldset neighbour for aging, which returns how long we sleep for */
1660 elt = clib_llist_prev (ip_neighbor_elt_pool, ipne_anchor, head);
1661 ip_neighbour_age_out (elt->ipne_index, now, &timeout);
1670 ip4_neighbor_age_process (vlib_main_t * vm,
1671 vlib_node_runtime_t * rt, vlib_frame_t * f)
1673 return (ip_neighbor_age_loop (vm, rt, f, AF_IP4));
1677 ip6_neighbor_age_process (vlib_main_t * vm,
1678 vlib_node_runtime_t * rt, vlib_frame_t * f)
1680 return (ip_neighbor_age_loop (vm, rt, f, AF_IP6));
1684 VLIB_REGISTER_NODE (ip4_neighbor_age_process_node,static) = {
1685 .function = ip4_neighbor_age_process,
1686 .type = VLIB_NODE_TYPE_PROCESS,
1687 .name = "ip4-neighbor-age-process",
1689 VLIB_REGISTER_NODE (ip6_neighbor_age_process_node,static) = {
1690 .function = ip6_neighbor_age_process,
1691 .type = VLIB_NODE_TYPE_PROCESS,
1692 .name = "ip6-neighbor-age-process",
1697 ip_neighbor_config (ip_address_family_t af, u32 limit, u32 age, bool recycle)
1699 ip_neighbor_db[af].ipndb_limit = limit;
1700 ip_neighbor_db[af].ipndb_recycle = recycle;
1701 ip_neighbor_db[af].ipndb_age = age;
1703 vlib_process_signal_event (vlib_get_main (),
1705 ip4_neighbor_age_process_node.index :
1706 ip6_neighbor_age_process_node.index),
1707 IP_NEIGHBOR_AGE_PROCESS_WAKEUP, 0);
1712 static clib_error_t *
1713 ip_neighbor_config_show (vlib_main_t * vm,
1714 unformat_input_t * input, vlib_cli_command_t * cmd)
1716 ip_address_family_t af;
1719 FOR_EACH_IP_ADDRESS_FAMILY(af) {
1720 vlib_cli_output (vm, "%U:", format_ip_address_family, af);
1721 vlib_cli_output (vm, " limit:%d, age:%d, recycle:%d",
1722 ip_neighbor_db[af].ipndb_limit,
1723 ip_neighbor_db[af].ipndb_age,
1724 ip_neighbor_db[af].ipndb_recycle);
1732 VLIB_CLI_COMMAND (show_ip_neighbor_cfg_cmd_node, static) = {
1733 .path = "show ip neighbor-config",
1734 .function = ip_neighbor_config_show,
1735 .short_help = "show ip neighbor-config",
1739 static clib_error_t *
1740 ip_neighbor_init (vlib_main_t * vm)
1743 ip4_add_del_interface_address_callback_t cb = {
1744 .function = ip_neighbor_add_del_interface_address_v4,
1746 vec_add1 (ip4_main.add_del_interface_address_callbacks, cb);
1749 ip6_add_del_interface_address_callback_t cb = {
1750 .function = ip_neighbor_add_del_interface_address_v6,
1752 vec_add1 (ip6_main.add_del_interface_address_callbacks, cb);
1755 ip4_table_bind_callback_t cb = {
1756 .function = ip_neighbor_table_bind_v4,
1758 vec_add1 (ip4_main.table_bind_callbacks, cb);
1761 ip6_table_bind_callback_t cb = {
1762 .function = ip_neighbor_table_bind_v6,
1764 vec_add1 (ip6_main.table_bind_callbacks, cb);
1767 ethernet_address_change_ctx_t ctx = {
1768 .function = ip_neighbor_ethernet_change_mac,
1769 .function_opaque = 0,
1771 vec_add1 (ethernet_main.address_change_callbacks, ctx);
1774 ipn_logger = vlib_log_register_class ("ip", "neighbor");
1776 ip_address_family_t af;
1778 FOR_EACH_IP_ADDRESS_FAMILY (af)
1779 ip_neighbor_list_head[af] =
1780 clib_llist_make_head (ip_neighbor_elt_pool, ipne_anchor);
1786 VLIB_INIT_FUNCTION (ip_neighbor_init) =
1788 .runs_after = VLIB_INITS("ip_main_init"),
1793 * fd.io coding-style-patch-verification: ON
1796 * eval: (c-set-style "gnu")