+ ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
+ vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
+
+ args.sw_if_index = sw_if_index;
+ args.flags = ETHERNET_ARP_ARGS_FLUSH;
+ args.ether_type = et;
+ clib_memcpy (&args.a, a, sizeof (*a));
+
+ vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
+ (u8 *) & args, sizeof (args));
+ return 0;
+}
+
+/**
+ * @brief Internally generated event to populate the ARP cache on an
+ * interface state change event.
+ * For static entries this will re-source the adjacencies.
+ *
+ * @param sw_if_index The interface on which the ARP entires are acted
+ * @param et The ether type of those ARP entries.
+ */
+static int
+vnet_arp_populate_ip4_over_ethernet (vnet_main_t * vnm,
+ u32 sw_if_index,
+ arp_ether_type_t et, void *a_arg)
+{
+ ethernet_arp_ip4_over_ethernet_address_t *a = a_arg;
+ vnet_arp_set_ip4_over_ethernet_rpc_args_t args;
+
+ args.sw_if_index = sw_if_index;
+ args.flags = ETHERNET_ARP_ARGS_POPULATE;
+ args.ether_type = et;
+ clib_memcpy (&args.a, a, sizeof (*a));
+
+ vl_api_rpc_call_main_thread (set_ip4_over_ethernet_rpc_callback,
+ (u8 *) & args, sizeof (args));
+ return 0;
+}
+
+/*
+ * arp_add_del_interface_address
+ *
+ * callback when an interface address is added or deleted
+ */
+static void
+arp_add_del_interface_address (ip4_main_t * im,
+ uword opaque,
+ u32 sw_if_index,
+ ip4_address_t * address,
+ u32 address_length,
+ u32 if_address_index, u32 is_del)
+{
+ /*
+ * Flush the ARP cache of all entries covered by the address
+ * that is being removed.
+ */
+ ethernet_arp_main_t *am = ðernet_arp_main;
+ ethernet_arp_ip4_entry_t *e;
+
+ if (vec_len (am->ethernet_arp_by_sw_if_index) < sw_if_index)
+ return;
+
+ if (is_del)
+ {
+ ethernet_arp_interface_t *eai;
+ u32 i, *to_delete = 0;
+ hash_pair_t *pair;
+
+ eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
+
+ hash_foreach_pair (pair, eai->arp_entries, (
+ {
+ e =
+ pool_elt_at_index
+ (am->ip4_entry_pool,
+ pair->value[0]);
+ if
+ (ip4_destination_matches_route
+ (im, &e->ip4_address,
+ address, address_length))
+ {
+ vec_add1 (to_delete,
+ e -
+ am->ip4_entry_pool);}
+ }
+ ));
+
+ for (i = 0; i < vec_len (to_delete); i++)
+ {
+ ethernet_arp_ip4_over_ethernet_address_t delme;
+ e = pool_elt_at_index (am->ip4_entry_pool, to_delete[i]);
+
+ clib_memcpy (&delme.ethernet, e->ethernet_address, 6);
+ delme.ip4.as_u32 = e->ip4_address.as_u32;
+
+ vnet_arp_flush_ip4_over_ethernet (vnet_get_main (),
+ e->sw_if_index,
+ ARP_ETHER_TYPE_BOTH, &delme);
+ }
+
+ vec_free (to_delete);
+ }
+}
+
+static void
+ethernet_arp_sw_interface_mpls_state_change (u32 sw_if_index, u32 is_enable)
+{
+ ethernet_arp_main_t *am = ðernet_arp_main;
+ ethernet_arp_ip4_entry_t *e;
+ ethernet_arp_interface_t *eai;
+ u32 i, *to_update = 0;
+ hash_pair_t *pair;
+
+ if (vec_len (am->ethernet_arp_by_sw_if_index) < sw_if_index)
+ return;
+
+ eai = &am->ethernet_arp_by_sw_if_index[sw_if_index];
+
+ if (is_enable)
+ eai->flags |= ETHERNET_ARP_INTERFACE_MPLS_ENABLE;
+ else
+ eai->flags &= ~ETHERNET_ARP_INTERFACE_MPLS_ENABLE;
+
+ hash_foreach_pair (pair, eai->arp_entries, (
+ {
+ vec_add1 (to_update,
+ pair->value[0]);
+ }
+ ));
+
+ for (i = 0; i < vec_len (to_update); i++)
+ {
+ ethernet_arp_ip4_over_ethernet_address_t updateme;
+ e = pool_elt_at_index (am->ip4_entry_pool, to_update[i]);
+
+ clib_memcpy (&updateme.ethernet, e->ethernet_address, 6);
+ updateme.ip4.as_u32 = e->ip4_address.as_u32;
+
+ if (is_enable)
+ {
+ vnet_arp_populate_ip4_over_ethernet (vnet_get_main (),
+ e->sw_if_index,
+ ARP_ETHER_TYPE_MPLS,
+ &updateme);
+ }
+ else
+ continue;
+
+ }
+ vec_free (to_update);
+}
+
+static clib_error_t *
+ethernet_arp_init (vlib_main_t * vm)
+{
+ ethernet_arp_main_t *am = ðernet_arp_main;
+ ip4_main_t *im = &ip4_main;
+ clib_error_t *error;
+ pg_node_t *pn;
+
+ if ((error = vlib_call_init_function (vm, ethernet_init)))
+ return error;