+ gbp_rule_t *gu;
+
+ pool_get_zero (gbp_rule_pool, gu);
+
+ gu->gu_nhs = nhs;
+ gu->gu_action = action;
+
+ return (gu - gbp_rule_pool);
+}
+
+index_t
+gbp_next_hop_alloc (const ip46_address_t * ip,
+ index_t grd, const mac_address_t * mac, index_t gbd)
+{
+ fib_protocol_t fproto;
+ gbp_next_hop_t *gnh;
+
+ pool_get_zero (gbp_next_hop_pool, gnh);
+
+ fib_node_init (&gnh->gnh_node, gbp_next_hop_fib_type);
+
+ ip46_address_copy (&gnh->gnh_ip, ip);
+ mac_address_copy (&gnh->gnh_mac, mac);
+
+ gnh->gnh_rd = grd;
+ gnh->gnh_bd = gbd;
+
+ FOR_EACH_FIB_IP_PROTOCOL (fproto) gnh->gnh_ai[fproto] = INDEX_INVALID;
+
+ return (gnh - gbp_next_hop_pool);
+}
+
+static inline gbp_next_hop_t *
+gbp_next_hop_get (index_t gui)
+{
+ return (pool_elt_at_index (gbp_next_hop_pool, gui));
+}
+
+static void
+gbp_contract_rules_free (index_t * rules)
+{
+ index_t *gui, *gnhi;
+
+ vec_foreach (gui, rules)
+ {
+ gbp_policy_node_t pnode;
+ fib_protocol_t fproto;
+ gbp_next_hop_t *gnh;
+ gbp_rule_t *gu;
+
+ gu = gbp_rule_get (*gui);
+
+ FOR_EACH_GBP_POLICY_NODE (pnode)
+ {
+ FOR_EACH_FIB_IP_PROTOCOL (fproto)
+ {
+ dpo_reset (&gu->gu_dpo[pnode][fproto]);
+ dpo_reset (&gu->gu_dpo[pnode][fproto]);
+ }
+ }
+
+ vec_foreach (gnhi, gu->gu_nhs)
+ {
+ fib_protocol_t fproto;
+
+ gnh = gbp_next_hop_get (*gnhi);
+ gbp_bridge_domain_unlock (gnh->gnh_bd);
+ gbp_route_domain_unlock (gnh->gnh_rd);
+ gbp_endpoint_child_remove (gnh->gnh_ge, gnh->gnh_sibling);
+ gbp_endpoint_unlock (GBP_ENDPOINT_SRC_RR, gnh->gnh_ge);
+
+ FOR_EACH_FIB_IP_PROTOCOL (fproto)
+ {
+ adj_unlock (gnh->gnh_ai[fproto]);
+ }
+ }
+ }
+ vec_free (rules);
+}
+
+static u8 *
+format_gbp_next_hop (u8 * s, va_list * args)
+{
+ index_t gnhi = va_arg (*args, index_t);
+ gbp_next_hop_t *gnh;
+
+ gnh = gbp_next_hop_get (gnhi);
+
+ s = format (s, "%U, %U, %U EP:%d",
+ format_mac_address_t, &gnh->gnh_mac,
+ format_gbp_bridge_domain, gnh->gnh_bd,
+ format_ip46_address, &gnh->gnh_ip, IP46_TYPE_ANY, gnh->gnh_ge);
+
+ return (s);
+}
+
+static u8 *
+format_gbp_rule_action (u8 * s, va_list * args)
+{
+ gbp_rule_action_t action = va_arg (*args, gbp_rule_action_t);
+
+ switch (action)
+ {
+#define _(v,a) case GBP_RULE_##v: return (format (s, "%s", a));
+ foreach_gbp_rule_action
+#undef _
+ }
+
+ return (format (s, "unknown"));
+}
+
+static u8 *
+format_gbp_hash_mode (u8 * s, va_list * args)
+{
+ gbp_hash_mode_t action = va_arg (*args, gbp_hash_mode_t);
+
+ switch (action)
+ {
+#define _(v,a) case GBP_HASH_MODE_##v: return (format (s, "%s", a));
+ foreach_gbp_hash_mode
+#undef _
+ }
+
+ return (format (s, "unknown"));
+}
+
+static u8 *
+format_gbp_policy_node (u8 * s, va_list * args)
+{
+ gbp_policy_node_t action = va_arg (*args, gbp_policy_node_t);
+
+ switch (action)
+ {
+#define _(v,a) case GBP_POLICY_NODE_##v: return (format (s, "%s", a));
+ foreach_gbp_policy_node
+#undef _
+ }
+
+ return (format (s, "unknown"));
+}
+
+static u8 *
+format_gbp_rule (u8 * s, va_list * args)
+{
+ index_t gui = va_arg (*args, index_t);
+ gbp_policy_node_t pnode;
+ fib_protocol_t fproto;
+ gbp_rule_t *gu;
+ index_t *gnhi;
+
+ gu = gbp_rule_get (gui);
+ s = format (s, "%U", format_gbp_rule_action, gu->gu_action);
+
+ switch (gu->gu_action)
+ {
+ case GBP_RULE_PERMIT:
+ case GBP_RULE_DENY:
+ break;
+ case GBP_RULE_REDIRECT:
+ s = format (s, ", %U", format_gbp_hash_mode, gu->gu_hash_mode);
+ break;
+ }
+
+ vec_foreach (gnhi, gu->gu_nhs)
+ {
+ s = format (s, "\n [%U]", format_gbp_next_hop, *gnhi);
+ }
+
+ FOR_EACH_GBP_POLICY_NODE (pnode)
+ {
+ s = format (s, "\n policy-%U", format_gbp_policy_node, pnode);
+
+ FOR_EACH_FIB_IP_PROTOCOL (fproto)
+ {
+ if (dpo_id_is_valid (&gu->gu_dpo[pnode][fproto]))
+ {
+ s =
+ format (s, "\n %U", format_dpo_id,
+ &gu->gu_dpo[pnode][fproto], 8);
+ }
+ }
+ }
+
+ return (s);
+}
+
+static void
+gbp_contract_mk_adj (gbp_next_hop_t * gnh, fib_protocol_t fproto)
+{
+ ethernet_header_t *eth;
+ gbp_endpoint_t *ge;
+ index_t old_ai;
+ u8 *rewrite;
+
+ old_ai = gnh->gnh_ai[fproto];
+ rewrite = NULL;
+ vec_validate (rewrite, sizeof (*eth) - 1);
+ eth = (ethernet_header_t *) rewrite;
+
+ GBP_CONTRACT_DBG ("...mk-adj: %U", format_gbp_next_hop,
+ gnh - gbp_next_hop_pool);
+
+ ge = gbp_endpoint_get (gnh->gnh_ge);
+
+ eth->type = clib_host_to_net_u16 ((fproto == FIB_PROTOCOL_IP4 ?
+ ETHERNET_TYPE_IP4 : ETHERNET_TYPE_IP6));
+ mac_address_to_bytes (gbp_route_domain_get_local_mac (), eth->src_address);
+ mac_address_to_bytes (&gnh->gnh_mac, eth->dst_address);
+
+ gnh->gnh_ai[fproto] =
+ adj_nbr_add_or_lock_w_rewrite (fproto,
+ fib_proto_to_link (fproto),
+ &gnh->gnh_ip, ge->ge_fwd.gef_itf, rewrite);
+
+ adj_unlock (old_ai);
+}
+
+static void
+gbp_contract_mk_lb (index_t gui, fib_protocol_t fproto)
+{
+ load_balance_path_t *paths = NULL;
+ gbp_policy_node_t pnode;
+ gbp_next_hop_t *gnh;
+ dpo_proto_t dproto;
+ gbp_rule_t *gu;
+ u32 ii;
+
+ u32 policy_nodes[] = {
+ [GBP_POLICY_NODE_L2] = gbp_policy_port_node.index,
+ [GBP_POLICY_NODE_IP4] = ip4_gbp_policy_dpo_node.index,
+ [GBP_POLICY_NODE_IP6] = ip6_gbp_policy_dpo_node.index,