return (-1);
}
+static_always_inline int
+ipsec_is_policy_inbound (ipsec_policy_t *policy)
+{
+ if (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
+ policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS ||
+ policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD)
+ return 1;
+
+ return 0;
+}
+
int
ipsec_add_del_policy (vlib_main_t * vm,
ipsec_policy_t * policy, int is_add, u32 * stat_index)
* Try adding the policy into fast path SPD first. Only adding to
* traditional SPD when failed.
**/
- if ((im->ipv4_fp_spd_is_enabled &&
+ if ((im->fp_spd_ipv4_out_is_enabled &&
+ PREDICT_TRUE (INDEX_INVALID !=
+ spd->fp_spd.ip4_out_lookup_hash_idx) &&
policy->type == IPSEC_SPD_POLICY_IP4_OUTBOUND) ||
- (im->ipv6_fp_spd_is_enabled &&
+ (im->fp_spd_ipv4_in_is_enabled &&
+ PREDICT_TRUE (INDEX_INVALID !=
+ spd->fp_spd.ip4_in_lookup_hash_idx) &&
+ (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
+ policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS ||
+ policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD)) ||
+ (im->fp_spd_ipv6_out_is_enabled &&
+ PREDICT_TRUE (INDEX_INVALID !=
+ spd->fp_spd.ip6_out_lookup_hash_idx) &&
policy->type == IPSEC_SPD_POLICY_IP6_OUTBOUND))
return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 1,
stat_index);
* traditional SPD when fp delete fails.
**/
- if ((im->ipv4_fp_spd_is_enabled &&
+ if ((im->fp_spd_ipv4_out_is_enabled &&
+ PREDICT_TRUE (INDEX_INVALID !=
+ spd->fp_spd.ip4_out_lookup_hash_idx) &&
policy->type == IPSEC_SPD_POLICY_IP4_OUTBOUND) ||
- (im->ipv6_fp_spd_is_enabled &&
+ (im->fp_spd_ipv4_in_is_enabled &&
+ PREDICT_TRUE (INDEX_INVALID !=
+ spd->fp_spd.ip4_in_lookup_hash_idx) &&
+ (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
+ policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS ||
+ policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD)) ||
+ (im->fp_spd_ipv6_out_is_enabled &&
+ PREDICT_TRUE (INDEX_INVALID !=
+ spd->fp_spd.ip6_out_lookup_hash_idx) &&
policy->type == IPSEC_SPD_POLICY_IP6_OUTBOUND))
- return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 0,
- stat_index);
+ {
+ if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
+ {
+ index_t sa_index = ipsec_sa_find_and_lock (policy->sa_id);
+
+ if (INDEX_INVALID == sa_index)
+ return VNET_API_ERROR_SYSCALL_ERROR_1;
+ policy->sa_index = sa_index;
+ ipsec_sa_unlock_id (policy->sa_id);
+ }
+ else
+ policy->sa_index = INDEX_INVALID;
+
+ return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 0,
+ stat_index);
+ }
vec_foreach_index (ii, (spd->policies[policy->type]))
{
}
static_always_inline void
-release_mask_type_index (ipsec_main_t *im, u32 mask_type_index)
+ipsec_fp_release_mask_type (ipsec_main_t *im, u32 mask_type_index)
{
ipsec_fp_mask_type_entry_t *mte =
pool_elt_at_index (im->fp_mask_types, mask_type_index);
}
static_always_inline u16
-get_highest_set_bit_u16 (u16 x)
+mask_out_highest_set_bit_u16 (u16 x)
{
x |= x >> 8;
x |= x >> 4;
x |= x >> 2;
x |= x >> 1;
- return x ^= x >> 1;
+ return ~x;
}
static_always_inline u32
-get_highest_set_bit_u32 (u32 x)
+mask_out_highest_set_bit_u32 (u32 x)
{
x |= x >> 16;
x |= x >> 8;
x |= x >> 4;
x |= x >> 2;
x |= x >> 1;
- return x ^= x >> 1;
+ return ~x;
}
static_always_inline u64
mask->lport = policy->lport.start ^ policy->lport.stop;
mask->rport = policy->rport.start ^ policy->rport.stop;
- mask->lport = get_highest_set_bit_u16 (mask->lport);
- mask->lport = ~(mask->lport - 1) & (~mask->lport);
+ mask->lport = mask_out_highest_set_bit_u16 (mask->lport);
- mask->rport = get_highest_set_bit_u16 (mask->rport);
- mask->rport = ~(mask->rport - 1) & (~mask->rport);
+ mask->rport = mask_out_highest_set_bit_u16 (mask->rport);
}
else
{
}
mask->protocol = (policy->protocol == IPSEC_POLICY_PROTOCOL_ANY) ? 0 : ~0;
+ mask->action = 0;
}
static_always_inline void
-ipsec_fp_ip4_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask)
+ipsec_fp_ip4_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask,
+ bool inbound)
{
u32 *pladdr_start = (u32 *) &policy->laddr.start.ip4;
u32 *pladdr_stop = (u32 *) &policy->laddr.stop.ip4;
* the bit itself. Remember that policy stores start and stop in the net
* order.
*/
- *plmask = get_highest_set_bit_u32 (clib_net_to_host_u32 (*plmask));
- *plmask = clib_host_to_net_u32 (~(*plmask - 1) & (~*plmask));
+ *plmask = clib_host_to_net_u32 (
+ mask_out_highest_set_bit_u32 (clib_net_to_host_u32 (*plmask)));
- *prmask = get_highest_set_bit_u32 (clib_net_to_host_u32 (*prmask));
- *prmask = clib_host_to_net_u32 (~(*prmask - 1) & (~*prmask));
+ *prmask = clib_host_to_net_u32 (
+ mask_out_highest_set_bit_u32 (clib_net_to_host_u32 (*prmask)));
- if (PREDICT_TRUE ((policy->protocol == IP_PROTOCOL_TCP) ||
- (policy->protocol == IP_PROTOCOL_UDP) ||
- (policy->protocol == IP_PROTOCOL_SCTP)))
+ if (inbound)
{
- mask->lport = policy->lport.start ^ policy->lport.stop;
- mask->rport = policy->rport.start ^ policy->rport.stop;
+ if (policy->type != IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT)
+ mask->spi = 0;
- mask->lport = get_highest_set_bit_u16 (mask->lport);
- mask->lport = ~(mask->lport - 1) & (~mask->lport);
-
- mask->rport = get_highest_set_bit_u16 (mask->rport);
- mask->rport = ~(mask->rport - 1) & (~mask->rport);
+ mask->protocol = 0;
}
else
{
- mask->lport = 0;
- mask->rport = 0;
+ mask->action = 0;
+ ipsec_fp_get_policy_ports_mask (policy, mask);
}
-
- mask->protocol = (policy->protocol == IPSEC_POLICY_PROTOCOL_ANY) ? 0 : ~0;
}
static_always_inline void
}
static_always_inline void
-ipsec_fp_get_policy_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *tuple)
+ipsec_fp_get_policy_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *tuple,
+ bool inbound)
{
memset (tuple, 0, sizeof (*tuple));
tuple->is_ipv6 = policy->is_ipv6;
tuple->raddr = policy->raddr.start.ip4;
}
+ if (inbound)
+ {
+
+ if ((policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
+ policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT) &&
+ policy->sa_index != INDEX_INVALID)
+ {
+ ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
+ tuple->spi = s->spi;
+ }
+ else
+ tuple->spi = INDEX_INVALID;
+ tuple->action = policy->type;
+ return;
+ }
+
tuple->protocol = policy->protocol;
tuple->lport = policy->lport.start;
tuple->rport = policy->rport.start;
}
+static_always_inline int
+ipsec_fp_mask_type_idx_cmp (ipsec_fp_mask_id_t *mask_id, u32 *idx)
+{
+ return mask_id->mask_type_idx == *idx;
+}
+
int
ipsec_fp_ip4_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd,
ipsec_policy_t *policy, u32 *stat_index)
{
- u32 mask_index;
+ u32 mask_index, searched_idx;
ipsec_policy_t *vp;
ipsec_fp_mask_type_entry_t *mte;
u32 policy_index;
ipsec_fp_5tuple_t mask, policy_5tuple;
int res;
-
- ipsec_fp_ip4_get_policy_mask (policy, &mask);
+ bool inbound = ipsec_is_policy_inbound (policy);
+ clib_bihash_16_8_t *bihash_table =
+ inbound ? pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
+ fp_spd->ip4_in_lookup_hash_idx) :
+ pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
+ fp_spd->ip4_out_lookup_hash_idx);
+
+ ipsec_fp_ip4_get_policy_mask (policy, &mask, inbound);
pool_get (im->policies, vp);
policy_index = vp - im->policies;
vlib_validate_combined_counter (&ipsec_spd_policy_counters, policy_index);
mte = im->fp_mask_types + mask_index;
policy->fp_mask_type_id = mask_index;
- ipsec_fp_get_policy_5tuple (policy, &policy_5tuple);
+ ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
fill_ip4_hash_policy_kv (&policy_5tuple, &mask, &kv);
- res = clib_bihash_search_inline_2_16_8 (&fp_spd->fp_ip4_lookup_hash, &kv,
- &result);
+ res = clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
if (res != 0)
{
/* key was not found crate a new entry */
vec_add1 (key_val->fp_policies_ids, policy_index);
- res = clib_bihash_add_del_16_8 (&fp_spd->fp_ip4_lookup_hash, &kv, 1);
+ res = clib_bihash_add_del_16_8 (bihash_table, &kv, 1);
+
if (res != 0)
goto error;
}
{
vec_add1 (result_val->fp_policies_ids, policy_index);
- res =
- clib_bihash_add_del_16_8 (&fp_spd->fp_ip4_lookup_hash, &result, 1);
+ res = clib_bihash_add_del_16_8 (bihash_table, &result, 1);
if (res != 0)
goto error;
{
clib_memcpy (&mte->mask, &mask, sizeof (mask));
mte->refcount = 0;
- vec_add1 (fp_spd->fp_mask_types[policy->type], mask_index);
}
+ searched_idx =
+ vec_search_with_function (fp_spd->fp_mask_ids[policy->type], &mask_index,
+ ipsec_fp_mask_type_idx_cmp);
+ if (~0 == searched_idx)
+ {
+ ipsec_fp_mask_id_t mask_id = { mask_index, 1 };
+ vec_add1 (fp_spd->fp_mask_ids[policy->type], mask_id);
+ }
+ else
+ (fp_spd->fp_mask_ids[policy->type] + searched_idx)->refcount++;
+
mte->refcount++;
vec_add1 (fp_spd->fp_policies[policy->type], policy_index);
clib_memcpy (vp, policy, sizeof (*vp));
error:
pool_put (im->policies, vp);
- release_mask_type_index (im, mask_index);
+ ipsec_fp_release_mask_type (im, mask_index);
return -1;
}
ipsec_policy_t *policy, u32 *stat_index)
{
- u32 mask_index;
+ u32 mask_index, searched_idx;
ipsec_policy_t *vp;
ipsec_fp_mask_type_entry_t *mte;
u32 policy_index;
ipsec_fp_5tuple_t mask, policy_5tuple;
int res;
- ipsec_fp_ip6_get_policy_mask (policy, &mask);
+ bool inbound = ipsec_is_policy_inbound (policy);
+ ipsec_fp_ip6_get_policy_mask (policy, &mask);
pool_get (im->policies, vp);
policy_index = vp - im->policies;
vlib_validate_combined_counter (&ipsec_spd_policy_counters, policy_index);
vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
*stat_index = policy_index;
mask_index = find_mask_type_index (im, &mask);
+ clib_bihash_40_8_t *bihash_table =
+ inbound ? pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
+ fp_spd->ip6_in_lookup_hash_idx) :
+ pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
+ fp_spd->ip6_out_lookup_hash_idx);
if (mask_index == ~0)
{
mte = im->fp_mask_types + mask_index;
policy->fp_mask_type_id = mask_index;
- ipsec_fp_get_policy_5tuple (policy, &policy_5tuple);
+ ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
fill_ip6_hash_policy_kv (&policy_5tuple, &mask, &kv);
- res = clib_bihash_search_inline_2_40_8 (&fp_spd->fp_ip6_lookup_hash, &kv,
- &result);
+ res = clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
if (res != 0)
{
/* key was not found crate a new entry */
vec_add1 (key_val->fp_policies_ids, policy_index);
- res = clib_bihash_add_del_40_8 (&fp_spd->fp_ip6_lookup_hash, &kv, 1);
+ res = clib_bihash_add_del_40_8 (bihash_table, &kv, 1);
if (res != 0)
goto error;
}
{
vec_add1 (result_val->fp_policies_ids, policy_index);
- res =
- clib_bihash_add_del_40_8 (&fp_spd->fp_ip6_lookup_hash, &result, 1);
+ res = clib_bihash_add_del_40_8 (bihash_table, &result, 1);
if (res != 0)
goto error;
{
clib_memcpy (&mte->mask, &mask, sizeof (mask));
mte->refcount = 0;
- vec_add1 (fp_spd->fp_mask_types[policy->type], mask_index);
}
+ searched_idx =
+ vec_search_with_function (fp_spd->fp_mask_ids[policy->type], &mask_index,
+ ipsec_fp_mask_type_idx_cmp);
+ if (~0 == searched_idx)
+ {
+ ipsec_fp_mask_id_t mask_id = { mask_index, 1 };
+ vec_add1 (fp_spd->fp_mask_ids[policy->type], mask_id);
+ }
+ else
+ (fp_spd->fp_mask_ids[policy->type] + searched_idx)->refcount++;
+
mte->refcount++;
vec_add1 (fp_spd->fp_policies[policy->type], policy_index);
clib_memcpy (vp, policy, sizeof (*vp));
error:
pool_put (im->policies, vp);
- release_mask_type_index (im, mask_index);
+ ipsec_fp_release_mask_type (im, mask_index);
return -1;
}
clib_bihash_kv_40_8_t result;
ipsec_fp_lookup_value_t *result_val =
(ipsec_fp_lookup_value_t *) &result.value;
+ bool inbound = ipsec_is_policy_inbound (policy);
+ clib_bihash_40_8_t *bihash_table =
+ inbound ? pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
+ fp_spd->ip6_in_lookup_hash_idx) :
+ pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
+ fp_spd->ip6_out_lookup_hash_idx);
ipsec_policy_t *vp;
u32 ii, iii, imt;
ipsec_fp_ip6_get_policy_mask (policy, &mask);
- ipsec_fp_get_policy_5tuple (policy, &policy_5tuple);
+ ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
fill_ip6_hash_policy_kv (&policy_5tuple, &mask, &kv);
- res = clib_bihash_search_inline_2_40_8 (&fp_spd->fp_ip6_lookup_hash, &kv,
- &result);
+ res = clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
if (res != 0)
return -1;
if (vec_len (result_val->fp_policies_ids) == 1)
{
vec_free (result_val->fp_policies_ids);
- clib_bihash_add_del_40_8 (&fp_spd->fp_ip6_lookup_hash,
- &result, 0);
+ clib_bihash_add_del_40_8 (bihash_table, &result, 0);
}
else
{
}
vec_del1 (fp_spd->fp_policies[policy->type], iii);
- vec_foreach_index (imt, fp_spd->fp_mask_types[policy->type])
+ vec_foreach_index (imt, fp_spd->fp_mask_ids[policy->type])
{
- if (*(fp_spd->fp_mask_types[policy->type] + imt) ==
- vp->fp_mask_type_id)
+ if ((fp_spd->fp_mask_ids[policy->type] + imt)
+ ->mask_type_idx == vp->fp_mask_type_id)
{
- ipsec_fp_mask_type_entry_t *mte = pool_elt_at_index (
- im->fp_mask_types, vp->fp_mask_type_id);
- if (mte->refcount == 1)
- vec_del1 (fp_spd->fp_mask_types[policy->type],
- imt);
+ if ((fp_spd->fp_mask_ids[policy->type] + imt)
+ ->refcount-- == 1)
+ vec_del1 (fp_spd->fp_mask_ids[policy->type], imt);
+
break;
}
}
continue;
else
{
- release_mask_type_index (im, vp->fp_mask_type_id);
+ ipsec_fp_release_mask_type (im, vp->fp_mask_type_id);
ipsec_sa_unlock (vp->sa_index);
pool_put (im->policies, vp);
return 0;
clib_bihash_kv_16_8_t result;
ipsec_fp_lookup_value_t *result_val =
(ipsec_fp_lookup_value_t *) &result.value;
-
+ bool inbound = ipsec_is_policy_inbound (policy);
ipsec_policy_t *vp;
u32 ii, iii, imt;
-
- ipsec_fp_ip4_get_policy_mask (policy, &mask);
- ipsec_fp_get_policy_5tuple (policy, &policy_5tuple);
+ clib_bihash_16_8_t *bihash_table =
+ inbound ? pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
+ fp_spd->ip4_in_lookup_hash_idx) :
+ pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
+ fp_spd->ip4_out_lookup_hash_idx);
+
+ ipsec_fp_ip4_get_policy_mask (policy, &mask, inbound);
+ ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
fill_ip4_hash_policy_kv (&policy_5tuple, &mask, &kv);
- res = clib_bihash_search_inline_2_16_8 (&fp_spd->fp_ip4_lookup_hash, &kv,
- &result);
+ res = clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
+
if (res != 0)
return -1;
if (vec_len (result_val->fp_policies_ids) == 1)
{
vec_free (result_val->fp_policies_ids);
- clib_bihash_add_del_16_8 (&fp_spd->fp_ip4_lookup_hash,
- &result, 0);
+ clib_bihash_add_del_16_8 (bihash_table, &result, 0);
}
else
{
}
vec_del1 (fp_spd->fp_policies[policy->type], iii);
- vec_foreach_index (imt, fp_spd->fp_mask_types[policy->type])
+ vec_foreach_index (imt, fp_spd->fp_mask_ids[policy->type])
{
- if (*(fp_spd->fp_mask_types[policy->type] + imt) ==
- vp->fp_mask_type_id)
+ if ((fp_spd->fp_mask_ids[policy->type] + imt)
+ ->mask_type_idx == vp->fp_mask_type_id)
{
- ipsec_fp_mask_type_entry_t *mte = pool_elt_at_index (
- im->fp_mask_types, vp->fp_mask_type_id);
- if (mte->refcount == 1)
- vec_del1 (fp_spd->fp_mask_types[policy->type],
- imt);
+ if ((fp_spd->fp_mask_ids[policy->type] + imt)
+ ->refcount-- == 1)
+ vec_del1 (fp_spd->fp_mask_ids[policy->type], imt);
+
break;
}
}
continue;
else
{
- release_mask_type_index (im, vp->fp_mask_type_id);
+ ipsec_fp_release_mask_type (im, vp->fp_mask_type_id);
ipsec_sa_unlock (vp->sa_index);
pool_put (im->policies, vp);
return 0;