.stat_segment_name = "/net/ipsec/policy",
};
-static int
-ipsec_spd_entry_sort (void *a1, void *a2)
-{
- ipsec_main_t *im = &ipsec_main;
- u32 *id1 = a1;
- u32 *id2 = a2;
- ipsec_policy_t *p1, *p2;
-
- p1 = pool_elt_at_index (im->policies, *id1);
- p2 = pool_elt_at_index (im->policies, *id2);
- if (p1 && p2)
- return p2->priority - p1->priority;
-
- return 0;
-}
-
int
ipsec_policy_mk_type (bool is_outbound,
bool is_ipv6,
{
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)
+ policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD ||
+ policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT ||
+ policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_BYPASS ||
+ policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD)
return 1;
return 0;
}
+static_always_inline int
+ipsec_is_fp_enabled (ipsec_main_t *im, ipsec_spd_t *spd,
+ ipsec_policy_t *policy)
+{
+ 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->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_in_is_enabled &&
+ PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip6_in_lookup_hash_idx) &&
+ (policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT ||
+ policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_BYPASS ||
+ policy->type == IPSEC_SPD_POLICY_IP6_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 1;
+ return 0;
+}
+
int
ipsec_add_del_policy (vlib_main_t * vm,
ipsec_policy_t * policy, int is_add, u32 * stat_index)
if (is_add)
{
u32 policy_index;
+ u32 i;
if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
{
* Try adding the policy into fast path SPD first. Only adding to
* traditional SPD when failed.
**/
- 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->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))
+ if (ipsec_is_fp_enabled (im, spd, policy))
return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 1,
stat_index);
vlib_validate_combined_counter (&ipsec_spd_policy_counters,
policy_index);
vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
- vec_add1 (spd->policies[policy->type], policy_index);
- vec_sort_with_function (spd->policies[policy->type],
- ipsec_spd_entry_sort);
+
+ vec_foreach_index (i, spd->policies[policy->type])
+ {
+ ipsec_policy_t *p =
+ pool_elt_at_index (im->policies, spd->policies[policy->type][i]);
+
+ if (p->priority <= vp->priority)
+ {
+ break;
+ }
+ }
+
+ vec_insert_elts (spd->policies[policy->type], &policy_index, 1, i);
+
*stat_index = policy_index;
}
else
* traditional SPD when fp delete fails.
**/
- 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->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))
+ if (ipsec_is_fp_enabled (im, spd, policy))
+
{
if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
{
}
mask->protocol = (policy->protocol == IPSEC_POLICY_PROTOCOL_ANY) ? 0 : ~0;
- mask->action = 0;
}
static_always_inline void
clib_memset_u8 (mask, 0xff, sizeof (ipsec_fp_5tuple_t));
clib_memset_u8 (&mask->l3_zero_pad, 0, sizeof (mask->l3_zero_pad));
+ if (inbound && (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT &&
+ policy->sa_index != INDEX_INVALID))
+ {
+ ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
+
+ if (ipsec_sa_is_set_IS_TUNNEL (s))
+ goto set_spi_mask;
+ }
+
/* find bits where start != stop */
*plmask = *pladdr_start ^ *pladdr_stop;
*prmask = *praddr_start ^ *praddr_stop;
*prmask = clib_host_to_net_u32 (
mask_out_highest_set_bit_u32 (clib_net_to_host_u32 (*prmask)));
+set_spi_mask:
if (inbound)
{
if (policy->type != IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT)
}
static_always_inline void
-ipsec_fp_ip6_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask)
+ipsec_fp_ip6_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask,
+ bool inbound)
{
u64 *pladdr_start = (u64 *) &policy->laddr.start;
u64 *pladdr_stop = (u64 *) &policy->laddr.stop;
clib_memset_u8 (mask, 0xff, sizeof (ipsec_fp_5tuple_t));
+ if (inbound && (policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT &&
+ policy->sa_index != INDEX_INVALID))
+ {
+ ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
+
+ if (ipsec_sa_is_set_IS_TUNNEL (s))
+ goto set_spi_mask;
+ }
+
*plmask = (*pladdr_start++ ^ *pladdr_stop++);
*prmask = (*praddr_start++ ^ *praddr_stop++);
}
else
*prmask = 0;
+set_spi_mask:
+ if (inbound)
+ {
+ if (policy->type != IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT)
+ mask->spi = 0;
- ipsec_fp_get_policy_ports_mask (policy, mask);
+ mask->protocol = 0;
+ }
+ else
+ {
+ mask->action = 0;
+ ipsec_fp_get_policy_ports_mask (policy, mask);
+ }
}
static_always_inline void
policy->sa_index != INDEX_INVALID)
{
ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
+
tuple->spi = s->spi;
+ if (ipsec_sa_is_set_IS_TUNNEL (s))
+ {
+ if (tuple->is_ipv6)
+ {
+ tuple->ip6_laddr = s->tunnel.t_dst.ip.ip6;
+ tuple->ip6_raddr = s->tunnel.t_src.ip.ip6;
+ }
+ else
+ {
+ tuple->laddr = s->tunnel.t_dst.ip.ip4;
+ tuple->raddr = s->tunnel.t_src.ip.ip4;
+ }
+ }
}
else
tuple->spi = INDEX_INVALID;
}
tuple->protocol = policy->protocol;
-
tuple->lport = policy->lport.start;
tuple->rport = policy->rport.start;
}
(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));
return 0;
int res;
bool inbound = ipsec_is_policy_inbound (policy);
- ipsec_fp_ip6_get_policy_mask (policy, &mask);
+ ipsec_fp_ip6_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);
(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));
return 0;
fp_spd->ip6_out_lookup_hash_idx);
ipsec_policy_t *vp;
- u32 ii, iii, imt;
+ u32 ii, imt;
- ipsec_fp_ip6_get_policy_mask (policy, &mask);
+ ipsec_fp_ip6_get_policy_mask (policy, &mask, inbound);
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 (bihash_table, &kv, &result);
if (res != 0)
return -1;
- res = -1;
vec_foreach_index (ii, result_val->fp_policies_ids)
{
vp =
pool_elt_at_index (im->policies, *(result_val->fp_policies_ids + ii));
if (ipsec_policy_is_equal (vp, policy))
{
- vec_foreach_index (iii, fp_spd->fp_policies[policy->type])
+ if (vec_len (result_val->fp_policies_ids) == 1)
+ {
+ vec_free (result_val->fp_policies_ids);
+ clib_bihash_add_del_40_8 (bihash_table, &result, 0);
+ }
+ else
+ vec_del1 (result_val->fp_policies_ids, ii);
+
+ vec_foreach_index (imt, fp_spd->fp_mask_ids[policy->type])
{
- if (*(fp_spd->fp_policies[policy->type] + iii) ==
- *(result_val->fp_policies_ids + ii))
+ if ((fp_spd->fp_mask_ids[policy->type] + imt)->mask_type_idx ==
+ vp->fp_mask_type_id)
{
- if (vec_len (result_val->fp_policies_ids) == 1)
- {
- vec_free (result_val->fp_policies_ids);
- clib_bihash_add_del_40_8 (bihash_table, &result, 0);
- }
- else
- {
- vec_del1 (result_val->fp_policies_ids, ii);
- }
- vec_del1 (fp_spd->fp_policies[policy->type], iii);
-
- vec_foreach_index (imt, fp_spd->fp_mask_ids[policy->type])
- {
- if ((fp_spd->fp_mask_ids[policy->type] + imt)
- ->mask_type_idx == vp->fp_mask_type_id)
- {
-
- if ((fp_spd->fp_mask_ids[policy->type] + imt)
- ->refcount-- == 1)
- vec_del1 (fp_spd->fp_mask_ids[policy->type], imt);
-
- break;
- }
- }
-
- res = 0;
+
+ if ((fp_spd->fp_mask_ids[policy->type] + imt)->refcount-- ==
+ 1)
+ vec_del1 (fp_spd->fp_mask_ids[policy->type], imt);
+
break;
}
}
- if (res != 0)
- continue;
- else
- {
- ipsec_fp_release_mask_type (im, vp->fp_mask_type_id);
- ipsec_sa_unlock (vp->sa_index);
- pool_put (im->policies, vp);
- return 0;
- }
+ ipsec_fp_release_mask_type (im, vp->fp_mask_type_id);
+ ipsec_sa_unlock (vp->sa_index);
+ pool_put (im->policies, vp);
+ return 0;
}
}
return -1;
(ipsec_fp_lookup_value_t *) &result.value;
bool inbound = ipsec_is_policy_inbound (policy);
ipsec_policy_t *vp;
- u32 ii, iii, imt;
+ u32 ii, imt;
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) :
if (res != 0)
return -1;
- res = -1;
vec_foreach_index (ii, result_val->fp_policies_ids)
{
vp =
pool_elt_at_index (im->policies, *(result_val->fp_policies_ids + ii));
if (ipsec_policy_is_equal (vp, policy))
{
- vec_foreach_index (iii, fp_spd->fp_policies[policy->type])
+ if (vec_len (result_val->fp_policies_ids) == 1)
{
- if (*(fp_spd->fp_policies[policy->type] + iii) ==
- *(result_val->fp_policies_ids + ii))
- {
- if (vec_len (result_val->fp_policies_ids) == 1)
- {
- vec_free (result_val->fp_policies_ids);
- clib_bihash_add_del_16_8 (bihash_table, &result, 0);
- }
- else
- {
- vec_del1 (result_val->fp_policies_ids, ii);
- }
- vec_del1 (fp_spd->fp_policies[policy->type], iii);
-
- vec_foreach_index (imt, fp_spd->fp_mask_ids[policy->type])
- {
- if ((fp_spd->fp_mask_ids[policy->type] + imt)
- ->mask_type_idx == vp->fp_mask_type_id)
- {
-
- if ((fp_spd->fp_mask_ids[policy->type] + imt)
- ->refcount-- == 1)
- vec_del1 (fp_spd->fp_mask_ids[policy->type], imt);
-
- break;
- }
- }
-
- res = 0;
- break;
- }
+ vec_free (result_val->fp_policies_ids);
+ clib_bihash_add_del_16_8 (bihash_table, &result, 0);
}
-
- if (res != 0)
- continue;
else
+ vec_del1 (result_val->fp_policies_ids, ii);
+
+ vec_foreach_index (imt, fp_spd->fp_mask_ids[policy->type])
{
- ipsec_fp_release_mask_type (im, vp->fp_mask_type_id);
- ipsec_sa_unlock (vp->sa_index);
- pool_put (im->policies, vp);
- return 0;
+ if ((fp_spd->fp_mask_ids[policy->type] + imt)->mask_type_idx ==
+ vp->fp_mask_type_id)
+ {
+
+ if ((fp_spd->fp_mask_ids[policy->type] + imt)->refcount-- ==
+ 1)
+ vec_del1 (fp_spd->fp_mask_ids[policy->type], imt);
+
+ break;
+ }
}
+ ipsec_fp_release_mask_type (im, vp->fp_mask_type_id);
+ ipsec_sa_unlock (vp->sa_index);
+ pool_put (im->policies, vp);
+ return 0;
}
}
return -1;