#include <plugins/gbp/gbp_policy_dpo.h>
#include <plugins/gbp/gbp_vxlan.h>
-#include <vnet/ethernet/arp.h>
#include <vnet/l2/l2_input.h>
#include <vnet/l2/l2_output.h>
#include <vnet/l2/feat_bitmap.h>
#include <vnet/l2/l2_fib.h>
#include <vnet/fib/fib_table.h>
-#include <vnet/ip/ip_neighbor.h>
+#include <vnet/ip-neighbor/ip_neighbor.h>
#include <vnet/fib/fib_walk.h>
+#include <vnet/vxlan-gbp/vxlan_gbp.h>
static const char *gbp_endpoint_attr_names[] = GBP_ENDPOINT_ATTR_NAMES;
*/
gbp_ep_db_t gbp_ep_db;
-fib_node_type_t gbp_endpoint_fib_type;
-
-vlib_log_class_t gbp_ep_logger;
+static fib_source_t gbp_fib_source_hi;
+static fib_source_t gbp_fib_source_low;
+static fib_node_type_t gbp_endpoint_fib_type;
+static vlib_log_class_t gbp_ep_logger;
#define GBP_ENDPOINT_DBG(...) \
vlib_log_debug (gbp_ep_logger, __VA_ARGS__);
#define GBP_ENDPOINT_INFO(...) \
vlib_log_notice (gbp_ep_logger, __VA_ARGS__);
-/**
- * GBP Endpoint inactive timeout (in seconds)
- * If a dynamically learned Endpoint has not been heard from in this
- * amount of time it is considered inactive and discarded
- */
-static u32 GBP_ENDPOINT_INACTIVE_TIME = 30;
-
/**
* Pool of GBP endpoints
*/
return (! !(ge->ge_fwd.gef_flags & GBP_ENDPOINT_FLAG_EXTERNAL));
}
+int
+gbp_endpoint_is_learnt (const gbp_endpoint_t * ge)
+{
+ if (0 == vec_len (ge->ge_locs))
+ return 0;
+
+ /* DP is the highest source so if present it will be first */
+ return (ge->ge_locs[0].gel_src == GBP_ENDPOINT_SRC_DP);
+}
+
static void
gbp_endpoint_extract_key_mac_itf (const clib_bihash_kv_16_8_t * key,
mac_address_t * mac, u32 * sw_if_index)
{
- mac_address_from_u64 (key->key[0], mac);
+ mac_address_from_u64 (mac, key->key[0]);
*sw_if_index = key->key[1];
}
return (ge - gbp_endpoint_pool);
}
-static ip46_type_t
-ip46_address_get_type (const ip46_address_t * a)
-{
- return (ip46_address_is_ip4 (a) ? IP46_TYPE_IP4 : IP46_TYPE_IP6);
-}
-
static int
gbp_endpoint_ip_is_equal (const fib_prefix_t * fp, const ip46_address_t * ip)
{
fib_node_init (&ge->ge_node, gbp_endpoint_fib_type);
gei = gbp_endpoint_index (ge);
ge->ge_key.gek_gbd =
- ge->ge_key.gek_grd = ge->ge_fwd.gef_itf = INDEX_INVALID;
+ ge->ge_key.gek_grd = ge->ge_fwd.gef_fib_index = INDEX_INVALID;
+ gbp_itf_hdl_reset (&ge->ge_fwd.gef_itf);
ge->ge_last_time = vlib_time_now (vlib_get_main ());
ge->ge_key.gek_gbd = gbp_bridge_domain_index (gbd);
gbp_endpoint_loc_destroy (gbp_endpoint_loc_t * gel)
{
gbp_endpoint_group_unlock (gel->gel_epg);
-
- if (gel->gel_flags & GBP_ENDPOINT_FLAG_REMOTE)
- {
- vxlan_gbp_tunnel_unlock (gel->gel_sw_if_index);
- }
+ gbp_itf_unlock (&gel->gel_itf);
}
static gbp_endpoint_loc_t *
gbp_endpoint_loc_t gel = {
.gel_src = src,
.gel_epg = INDEX_INVALID,
- .gel_sw_if_index = INDEX_INVALID,
+ .gel_itf = GBP_ITF_HDL_INVALID,
.gel_locks = 0,
};
u32 pos;
}
static void
-gbp_endpoint_loc_update (gbp_endpoint_loc_t * gel,
+gbp_endpoint_loc_update (const gbp_endpoint_t * ge,
+ gbp_endpoint_loc_t * gel,
+ const gbp_bridge_domain_t * gb,
u32 sw_if_index,
index_t ggi,
gbp_endpoint_flags_t flags,
gbp_endpoint_n_learned (is_learnt - was_learnt);
- if (INDEX_INVALID == gel->gel_epg)
- {
- gel->gel_epg = ggi;
- if (INDEX_INVALID != gel->gel_epg)
- {
- gbp_endpoint_group_lock (gel->gel_epg);
- }
- }
- else
- {
- ASSERT (gel->gel_epg == ggi);
- }
+ /*
+ * update the EPG
+ */
+ gbp_endpoint_group_lock (ggi);
+ gbp_endpoint_group_unlock (gel->gel_epg);
+ gel->gel_epg = ggi;
if (gel->gel_flags & GBP_ENDPOINT_FLAG_REMOTE)
{
if (NULL != tun_dst)
ip46_address_copy (&gel->tun.gel_dst, tun_dst);
+ if (ip46_address_is_multicast (&gel->tun.gel_src))
+ {
+ /*
+ * we learnt the EP from the multicast tunnel.
+ * Create a unicast TEP from the packet's source
+ * and the fixed address of the BD's parent tunnel
+ */
+ const gbp_vxlan_tunnel_t *gt;
+
+ gt = gbp_vxlan_tunnel_get (gb->gb_vni);
+
+ if (NULL != gt)
+ {
+ ip46_address_copy (&gel->tun.gel_src, >->gt_src);
+ sw_if_index = gt->gt_sw_if_index;
+ }
+ }
+
/*
* the input interface may be the parent GBP-vxlan interface,
* create a child vlxan-gbp tunnel and use that as the endpoint's
* interface.
*/
- if (~0 != gel->gel_sw_if_index)
- vxlan_gbp_tunnel_unlock (gel->gel_sw_if_index);
+ gbp_itf_hdl_t old = gel->gel_itf;
switch (gbp_vxlan_tunnel_get_type (sw_if_index))
{
case GBP_VXLAN_TEMPLATE_TUNNEL:
gel->tun.gel_parent_sw_if_index = sw_if_index;
- gel->gel_sw_if_index =
- gbp_vxlan_tunnel_clone_and_lock (sw_if_index,
- &gel->tun.gel_src,
- &gel->tun.gel_dst);
+ gel->gel_itf = gbp_vxlan_tunnel_clone_and_lock (sw_if_index,
+ &gel->tun.gel_src,
+ &gel->tun.gel_dst);
break;
case VXLAN_GBP_TUNNEL:
gel->tun.gel_parent_sw_if_index =
vxlan_gbp_tunnel_get_parent (sw_if_index);
- gel->gel_sw_if_index = sw_if_index;
- vxlan_gbp_tunnel_lock (gel->gel_sw_if_index);
+ gel->gel_itf = vxlan_gbp_tunnel_lock_itf (sw_if_index);
break;
}
+
+ gbp_itf_unlock (&old);
}
else
{
- gel->gel_sw_if_index = sw_if_index;
+ gel->gel_itf = gbp_itf_l2_add_and_lock (sw_if_index,
+ ge->ge_key.gek_gbd);
}
}
gbp_endpoint_fwd_t *gef;
const fib_prefix_t *pfx;
index_t *ai;
- index_t gei;
- gei = gbp_endpoint_index (ge);
gbd = gbp_bridge_domain_get (ge->ge_key.gek_gbd);
gef = &ge->ge_fwd;
*/
if (gbp_endpoint_is_remote (ge))
{
- fib_table_entry_special_remove (fib_index, pfx, FIB_SOURCE_PLUGIN_HI);
+ fib_table_entry_special_remove (fib_index, pfx, gbp_fib_source_hi);
}
- fib_table_entry_delete (fib_index, pfx, FIB_SOURCE_PLUGIN_LOW);
+ fib_table_entry_delete (fib_index, pfx, gbp_fib_source_low);
}
vec_foreach (ai, gef->gef_adjs)
{
adj_unlock (*ai);
}
- if (INDEX_INVALID != gef->gef_itf)
+ if (gbp_itf_hdl_is_valid (gef->gef_itf))
{
l2fib_del_entry (ge->ge_key.gek_mac.bytes,
- gbd->gb_bd_index, gef->gef_itf);
- gbp_itf_set_l2_input_feature (gef->gef_itf, gei, (L2INPUT_FEAT_NONE));
- gbp_itf_set_l2_output_feature (gef->gef_itf, gei, L2OUTPUT_FEAT_NONE);
-
- gbp_itf_unlock (gef->gef_itf);
- gef->gef_itf = INDEX_INVALID;
+ gbd->gb_bd_index,
+ gbp_itf_get_sw_if_index (gef->gef_itf));
}
+ gbp_itf_unlock (&gef->gef_itf);
vec_free (gef->gef_adjs);
}
static void
gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
{
- const gbp_route_domain_t *grd;
const gbp_bridge_domain_t *gbd;
const gbp_endpoint_group_t *gg;
+ const gbp_route_domain_t *grd;
gbp_endpoint_loc_t *gel;
gbp_endpoint_fwd_t *gef;
const fib_prefix_t *pfx;
if (INDEX_INVALID != gel->gel_epg)
{
gg = gbp_endpoint_group_get (gel->gel_epg);
- gef->gef_epg_id = gg->gg_id;
+ gef->gef_sclass = gg->gg_sclass;
}
else
{
gg = NULL;
}
- gef->gef_itf = gbp_itf_add_and_lock (gel->gel_sw_if_index,
- gbd->gb_bd_index);
+ gef->gef_itf = gbp_itf_clone_and_lock (gel->gel_itf);
if (!mac_address_is_zero (&ge->ge_key.gek_mac))
{
- gbp_itf_set_l2_input_feature (gef->gef_itf, gei, L2INPUT_FEAT_GBP_FWD);
+ gbp_itf_l2_set_input_feature (gef->gef_itf, L2INPUT_FEAT_GBP_FWD);
if (gbp_endpoint_is_remote (ge) || gbp_endpoint_is_external (ge))
{
* bridged packets to external endpoints should be classifed
* based on the EP's/BD's EPG
*/
- gbp_itf_set_l2_output_feature (gef->gef_itf, gei,
+ gbp_itf_l2_set_output_feature (gef->gef_itf,
L2OUTPUT_FEAT_GBP_POLICY_MAC);
}
else
{
- gbp_endpoint_add_itf (gef->gef_itf, gei);
- gbp_itf_set_l2_output_feature (gef->gef_itf, gei,
+ gbp_endpoint_add_itf (gbp_itf_get_sw_if_index (gef->gef_itf), gei);
+ gbp_itf_l2_set_output_feature (gef->gef_itf,
L2OUTPUT_FEAT_GBP_POLICY_PORT);
}
l2fib_add_entry (ge->ge_key.gek_mac.bytes,
gbd->gb_bd_index,
- gef->gef_itf, L2FIB_ENTRY_RESULT_FLAG_STATIC);
+ gbp_itf_get_sw_if_index (gef->gef_itf),
+ L2FIB_ENTRY_RESULT_FLAG_STATIC);
}
vec_foreach (pfx, ge->ge_key.gek_ips)
rewrite = NULL;
grd = gbp_route_domain_get (ge->ge_key.gek_grd);
fib_index = grd->grd_fib_index[pfx->fp_proto];
+ gef->gef_fib_index = fib_index;
bd_add_del_ip_mac (gbd->gb_bd_index, fib_proto_to_ip46 (pfx->fp_proto),
&pfx->fp_addr, &ge->ge_key.gek_mac, 1);
* tunnel since the BD will not contain the EP's MAC since it was
* L3 learned. The dst MAC address used is the 'BD's MAC'.
*/
- ip_sw_if_index = gef->gef_itf;
+ ip_sw_if_index = gbp_itf_get_sw_if_index (gef->gef_itf);
mac_address_to_bytes (gbp_route_domain_get_local_mac (),
eth->src_address);
}
fib_table_entry_path_add (fib_index, pfx,
- FIB_SOURCE_PLUGIN_LOW,
+ gbp_fib_source_low,
FIB_ENTRY_FLAG_NONE,
fib_proto_to_dpo (pfx->fp_proto),
&pfx->fp_addr, ip_sw_if_index,
* is applied
*/
gbp_policy_dpo_add_or_lock (fib_proto_to_dpo (pfx->fp_proto),
- gg->gg_id, ~0, &policy_dpo);
+ grd->grd_scope,
+ gg->gg_sclass, ~0, &policy_dpo);
fib_table_entry_special_dpo_add (fib_index, pfx,
- FIB_SOURCE_PLUGIN_HI,
+ gbp_fib_source_hi,
FIB_ENTRY_FLAG_INTERPOSE,
&policy_dpo);
dpo_reset (&policy_dpo);
*/
if (gbp_endpoint_is_local (ge) && ~0 != gg->gg_uplink_sw_if_index)
{
- gbp_endpoint_add_itf (gef->gef_itf, gei);
- if (FIB_PROTOCOL_IP4 == pfx->fp_proto)
- send_ip4_garp_w_addr (vlib_get_main (),
- &pfx->fp_addr.ip4,
- gg->gg_uplink_sw_if_index);
- else
- send_ip6_na_w_addr (vlib_get_main (),
- &pfx->fp_addr.ip6,
- gg->gg_uplink_sw_if_index);
+ gbp_endpoint_add_itf (gbp_itf_get_sw_if_index (gef->gef_itf),
+ gei);
+ ip_neighbor_advertise (vlib_get_main (),
+ (FIB_PROTOCOL_IP4 == pfx->fp_proto ?
+ IP46_TYPE_IP4 :
+ IP46_TYPE_IP6),
+ &pfx->fp_addr, gg->gg_uplink_sw_if_index);
}
}
}
- if (gbp_endpoint_is_local (ge) && !gbp_endpoint_is_external (ge))
+ if (gbp_endpoint_is_external (ge))
+ {
+ gbp_itf_l2_set_input_feature (gef->gef_itf,
+ L2INPUT_FEAT_GBP_LPM_CLASSIFY);
+ }
+ else if (gbp_endpoint_is_local (ge))
{
/*
* non-remote endpoints (i.e. those not arriving on iVXLAN
if (NULL != gg && ~0 != gg->gg_uplink_sw_if_index)
feats |= L2INPUT_FEAT_GBP_FWD;
- gbp_itf_set_l2_input_feature (gef->gef_itf, gei, feats);
+ gbp_itf_l2_set_input_feature (gef->gef_itf, feats);
}
/*
u32 sw_if_index,
const ip46_address_t * ips,
const mac_address_t * mac,
- index_t gbdi, index_t grdi, epg_id_t epg_id,
+ index_t gbdi, index_t grdi,
+ sclass_t sclass,
gbp_endpoint_flags_t flags,
const ip46_address_t * tun_src,
const ip46_address_t * tun_dst, u32 * handle)
* we need to determine the bridge-domain, either from the EPG or
* the BD passed
*/
- if (EPG_INVALID != epg_id)
+ if (SCLASS_INVALID != sclass)
{
- ggi = gbp_endpoint_group_find (epg_id);
+ ggi = gbp_endpoint_group_find (sclass);
if (INDEX_INVALID == ggi)
return (VNET_API_ERROR_NO_SUCH_ENTRY);
gei = gbp_endpoint_index (ge);
gel = gbp_endpoint_loc_find_or_add (ge, src);
- gbp_endpoint_loc_update (gel, sw_if_index, ggi, flags, tun_src, tun_dst);
+ gbp_endpoint_loc_update (ge, gel, gbd, sw_if_index, ggi, flags,
+ tun_src, tun_dst);
if (src <= best)
{
ip46_address_t ip = ip46_address_initializer, *ips = NULL;
mac_address_t mac = ZERO_MAC_ADDRESS;
vnet_main_t *vnm = vnet_get_main ();
- u32 epg_id = EPG_INVALID;
+ u32 sclass = SCLASS_INVALID;
u32 handle = INDEX_INVALID;
u32 sw_if_index = ~0;
+ u32 flags = GBP_ENDPOINT_FLAG_NONE;
u8 add = 1;
int rv;
add = 1;
else if (unformat (input, "del"))
add = 0;
- else if (unformat (input, "epg %d", &epg_id))
+ else if (unformat (input, "sclass %d", &sclass))
;
else if (unformat (input, "handle %d", &handle))
;
vec_add1 (ips, ip);
else if (unformat (input, "mac %U", unformat_mac_address, &mac))
;
+ else if (unformat (input, "flags 0x%x", &flags))
+ ;
else
break;
}
{
if (~0 == sw_if_index)
return clib_error_return (0, "interface must be specified");
- if (EPG_INVALID == epg_id)
- return clib_error_return (0, "EPG-ID must be specified");
+ if (SCLASS_INVALID == sclass)
+ return clib_error_return (0, "SCLASS must be specified");
rv =
gbp_endpoint_update_and_lock (GBP_ENDPOINT_SRC_CP,
sw_if_index, ips, &mac,
INDEX_INVALID, INDEX_INVALID,
- epg_id,
- GBP_ENDPOINT_FLAG_NONE,
- NULL, NULL, &handle);
+ sclass, flags, NULL, NULL, &handle);
if (rv)
return clib_error_return (0, "GBP Endpoint update returned %d", rv);
* Configure a GBP Endpoint
*
* @cliexpar
- * @cliexstart{set gbp endpoint [del] <interface> epg <ID> ip <IP>}
+ * @cliexstart{gbp endpoint del <handle> | [add] <interface> sclass <SCLASS> ip <IP> mac <MAC> [flags <flags>]}
* @cliexend
?*/
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (gbp_endpoint_cli_node, static) = {
.path = "gbp endpoint",
- .short_help = "gbp endpoint [del] <interface> epg <ID> ip <IP> mac <MAC>",
+ .short_help = "gbp endpoint del <handle> | [add] <interface> sclass <SCLASS> ip <IP> mac <MAC> [flags <flags>]",
.function = gbp_endpoint_cli,
};
/* *INDENT-ON* */
gbp_endpoint_fwd_t *gef = va_arg (*args, gbp_endpoint_fwd_t *);
s = format (s, "fwd:");
- s = format (s, "\n itf:[%U]", format_gbp_itf, gef->gef_itf);
+ s = format (s, "\n itf:[%U]", format_gbp_itf_hdl, gef->gef_itf);
if (GBP_ENDPOINT_FLAG_NONE != gef->gef_flags)
{
s = format (s, " flags:%U", format_gbp_endpoint_flags, gef->gef_flags);
gbp_endpoint_loc_t *gel = va_arg (*args, gbp_endpoint_loc_t *);
s = format (s, "%U", format_gbp_endpoint_src, gel->gel_src);
- s =
- format (s, "\n %U", format_vnet_sw_if_index_name, vnet_get_main (),
- gel->gel_sw_if_index);
- s = format (s, " EPG:%d", gel->gel_epg);
+ s = format (s, "\n EPG:%d [%U]", gel->gel_epg,
+ format_gbp_itf_hdl, gel->gel_itf);
if (GBP_ENDPOINT_FLAG_NONE != gel->gel_flags)
{
return (WALK_CONTINUE);
}
-static void
-gbp_endpoint_walk_ip_itf (const clib_bihash_kv_24_8_t * kvp, void *arg)
+static int
+gbp_endpoint_walk_ip_itf (clib_bihash_kv_24_8_t * kvp, void *arg)
{
ip46_address_t ip;
vlib_main_t *vm;
format_ip46_address, &ip, IP46_TYPE_ANY,
format_vnet_sw_if_index_name, vnet_get_main (),
sw_if_index, kvp->value);
+ return (BIHASH_WALK_CONTINUE);
}
-static void
-gbp_endpoint_walk_mac_itf (const clib_bihash_kv_16_8_t * kvp, void *arg)
+static int
+gbp_endpoint_walk_mac_itf (clib_bihash_kv_16_8_t * kvp, void *arg)
{
mac_address_t mac;
vlib_main_t *vm;
format_mac_address_t, &mac,
format_vnet_sw_if_index_name, vnet_get_main (),
sw_if_index, kvp->value);
+ return (BIHASH_WALK_CONTINUE);
}
static clib_error_t *
static void
gbp_endpoint_check (index_t gei, f64 start_time)
{
+ gbp_endpoint_group_t *gg;
gbp_endpoint_loc_t *gel;
gbp_endpoint_t *ge;
ge = gbp_endpoint_get (gei);
gel = gbp_endpoint_loc_find (ge, GBP_ENDPOINT_SRC_DP);
- if ((NULL != gel) &&
- ((start_time - ge->ge_last_time) > GBP_ENDPOINT_INACTIVE_TIME))
+ if (NULL != gel)
{
- gbp_endpoint_unlock (GBP_ENDPOINT_SRC_DP, gei);
+ gg = gbp_endpoint_group_get (gel->gel_epg);
+
+ if ((start_time - ge->ge_last_time) >
+ gg->gg_retention.remote_ep_timeout)
+ {
+ gbp_endpoint_unlock (GBP_ENDPOINT_SRC_DP, gei);
+ }
}
}
f64 last_start, start_time, delta_t;
int i, j, k;
+ if (!gte_table->instantiated)
+ return;
+
delta_t = 0;
last_start = start_time = vlib_time_now (vm);
f64 last_start, start_time, delta_t;
int i, j, k;
+ if (!gte_table->instantiated)
+ return;
+
delta_t = 0;
last_start = start_time = vlib_time_now (vm);
gbp_endpoint_scan_l3 (vm);
}
-void
-gbp_learn_set_inactive_threshold (u32 threshold)
-{
- GBP_ENDPOINT_INACTIVE_TIME = threshold;
-
- vlib_process_signal_event (vlib_get_main (),
- gbp_scanner_node.index,
- GBP_ENDPOINT_SCAN_SET_TIME, 0);
-}
-
-f64
-gbp_endpoint_scan_threshold (void)
-{
- return (GBP_ENDPOINT_INACTIVE_TIME);
-}
-
static fib_node_t *
gbp_endpoint_get_node (fib_node_index_t index)
{
gbp_ep_logger = vlib_log_register_class ("gbp", "ep");
gbp_endpoint_fib_type = fib_node_register_new_type (&gbp_endpoint_vft);
+ gbp_fib_source_hi = fib_source_allocate ("gbp-endpoint-hi",
+ FIB_SOURCE_PRIORITY_HI,
+ FIB_SOURCE_BH_SIMPLE);
+ gbp_fib_source_low = fib_source_allocate ("gbp-endpoint-low",
+ FIB_SOURCE_PRIORITY_LOW,
+ FIB_SOURCE_BH_SIMPLE);
return (NULL);
}