#include <vnet/fib/fib_table.h>
#include <vnet/ip/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;
#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
*/
int
gbp_endpoint_is_remote (const gbp_endpoint_t * ge)
{
- return (ge->ge_fwd.gef_flags & GBP_ENDPOINT_FLAG_REMOTE);
+ return (! !(ge->ge_fwd.gef_flags & GBP_ENDPOINT_FLAG_REMOTE));
+}
+
+int
+gbp_endpoint_is_local (const gbp_endpoint_t * ge)
+{
+ return (!(ge->ge_fwd.gef_flags & GBP_ENDPOINT_FLAG_REMOTE));
+}
+
+int
+gbp_endpoint_is_external (const gbp_endpoint_t * ge)
+{
+ 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];
}
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_itf = ge->ge_fwd.gef_fib_index = INDEX_INVALID;
ge->ge_last_time = vlib_time_now (vlib_get_main ());
ge->ge_key.gek_gbd = gbp_bridge_domain_index (gbd);
static void
gbp_endpoint_loc_update (gbp_endpoint_loc_t * gel,
+ const gbp_bridge_domain_t * gb,
u32 sw_if_index,
index_t ggi,
gbp_endpoint_flags_t flags,
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
{
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_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);
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
{
{
gbp_itf_set_l2_input_feature (gef->gef_itf, gei, L2INPUT_FEAT_GBP_FWD);
- if (gbp_endpoint_is_remote (ge))
+ 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,
L2OUTPUT_FEAT_GBP_POLICY_MAC);
}
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);
ip_sw_if_index, rewrite);
vec_add1 (gef->gef_adjs, ai);
+ /*
+ * if the endpoint is external then routed packet to it must be
+ * classifed to the BD's EPG. but this will happen anyway with
+ * the GBP_MAC classification.
+ */
+
if (NULL != gg)
{
if (gbp_endpoint_is_remote (ge))
* 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,
FIB_ENTRY_FLAG_INTERPOSE,
&policy_dpo);
+ dpo_reset (&policy_dpo);
}
/*
* that if this EP has moved from some other place in the
* 'fabric', upstream devices are informed
*/
- if (!gbp_endpoint_is_remote (ge) && ~0 != gg->gg_uplink_sw_if_index)
+ 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)
}
}
- if (!gbp_endpoint_is_remote (ge))
+ if (gbp_endpoint_is_external (ge))
+ {
+ gbp_itf_set_l2_input_feature (gef->gef_itf, gei,
+ L2INPUT_FEAT_GBP_LPM_CLASSIFY);
+ }
+ else if (gbp_endpoint_is_local (ge))
{
/*
* non-remote endpoints (i.e. those not arriving on iVXLAN
* tunnels) need to be classifed based on the the input interface.
* We enable the GBP-FWD feature only if the group has an uplink
* interface (on which the GBP-FWD feature would send UU traffic).
+ * External endpoints get classified based on an LPM match
*/
l2input_feat_masks_t feats = L2INPUT_FEAT_GBP_SRC_CLASSIFY;
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 (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;
u8 add = 1;
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))
;
{
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,
+ sclass,
GBP_ENDPOINT_FLAG_NONE,
NULL, NULL, &handle);
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);
+ }
}
}
gbp_endpoint_scan_l3 (vm);
}
-void
-gbp_learn_set_inactive_threshold (u32 threshold)
-{
- GBP_ENDPOINT_INACTIVE_TIME = threshold;
-}
-
-f64
-gbp_endpoint_scan_threshold (void)
-{
- return (GBP_ENDPOINT_INACTIVE_TIME);
-}
-
static fib_node_t *
gbp_endpoint_get_node (fib_node_index_t index)
{