+u8 *
+format_ip_neighbor_flags (u8 * s, va_list * args)
+{
+ const ip_neighbor_flags_t flags = va_arg (*args, int);
+
+ if (flags & IP_NEIGHBOR_FLAG_STATIC)
+ s = format (s, "S");
+
+ if (flags & IP_NEIGHBOR_FLAG_DYNAMIC)
+ s = format (s, "D");
+
+ if (flags & IP_NEIGHBOR_FLAG_NO_FIB_ENTRY)
+ s = format (s, "N");
+
+ return s;
+}
+
+int
+ip_neighbor_add (const ip46_address_t * ip,
+ ip46_type_t type,
+ const mac_address_t * mac,
+ u32 sw_if_index,
+ ip_neighbor_flags_t flags, u32 * stats_index)
+{
+ fib_protocol_t fproto;
+ vnet_link_t linkt;
+ int rv;
+
+ /*
+ * there's no validation here of the ND/ARP entry being added.
+ * The expectation is that the FIB will ensure that nothing bad
+ * will come of adding bogus entries.
+ */
+ if (IP46_TYPE_IP6 == type)
+ {
+ rv = vnet_set_ip6_ethernet_neighbor (vlib_get_main (),
+ sw_if_index, &ip->ip6, mac, flags);
+ fproto = FIB_PROTOCOL_IP6;
+ linkt = VNET_LINK_IP6;
+ }
+ else
+ {
+ ethernet_arp_ip4_over_ethernet_address_t a = {
+ .ip4 = ip->ip4,
+ .mac = *mac,
+ };
+
+ rv =
+ vnet_arp_set_ip4_over_ethernet (vnet_get_main (), sw_if_index, &a,
+ flags);
+ fproto = FIB_PROTOCOL_IP4;
+ linkt = VNET_LINK_IP4;
+ }
+
+ if (0 == rv && stats_index)
+ *stats_index = adj_nbr_find (fproto, linkt, ip, sw_if_index);
+
+ return (rv);
+}
+
+int
+ip_neighbor_del (const ip46_address_t * ip, ip46_type_t type, u32 sw_if_index)
+{
+ int rv;
+
+ if (IP46_TYPE_IP6 == type)
+ {
+ rv = vnet_unset_ip6_ethernet_neighbor (vlib_get_main (),
+ sw_if_index, &ip->ip6);
+ }
+ else
+ {
+ ethernet_arp_ip4_over_ethernet_address_t a = {
+ .ip4 = ip->ip4,
+ };
+
+ rv =
+ vnet_arp_unset_ip4_over_ethernet (vnet_get_main (), sw_if_index, &a);
+ }
+
+ return (rv);
+}
+