164 lines
4.6 KiB
Diff
164 lines
4.6 KiB
Diff
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
|
|
index 62486f8..3cbe4f8 100644
|
|
--- a/net/xfrm/xfrm_policy.c
|
|
+++ b/net/xfrm/xfrm_policy.c
|
|
@@ -48,6 +48,11 @@
|
|
#include <net/inet_dscp.h>
|
|
|
|
#include "xfrm_hash.h"
|
|
+#ifdef IPSEC_FLOW_CACHE
|
|
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
|
|
+#include "ipsec_flow.h"
|
|
+#endif
|
|
+#endif
|
|
|
|
#define XFRM_QUEUE_TMO_MIN ((unsigned)(HZ/10))
|
|
#define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ))
|
|
@@ -179,6 +184,15 @@ static struct xfrm_policy_afinfo const __rcu *xfrm_policy_afinfo[AF_INET6 + 1]
|
|
|
|
static struct kmem_cache *xfrm_dst_cache __ro_after_init;
|
|
|
|
+#ifdef IPSEC_FLOW_CACHE
|
|
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
|
|
+extern int ipsec_nlkey_flow(u16 xfrm_nr, u16 *xfrm_handle,
|
|
+ const struct flowi *fl, u16 family, u16 dir, u16 ignore_neigh);
|
|
+int ipsec_flow_init(struct net *net);
|
|
+void ipsec_flow_fini(struct net *net);
|
|
+#endif
|
|
+#endif
|
|
+
|
|
static struct rhashtable xfrm_policy_inexact_table;
|
|
static const struct rhashtable_params xfrm_pol_inexact_params;
|
|
|
|
@@ -2599,6 +2613,17 @@ static dscp_t xfrm_get_dscp(const struct flowi *fl, int family)
|
|
return 0;
|
|
}
|
|
|
|
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
|
|
+int xfrm_get_tos(const struct flowi *fl, int family)
|
|
+{
|
|
+ if (family == AF_INET)
|
|
+ return inet_dscp_to_dsfield(fl->u.ip4.flowi4_dscp) & INET_DSCP_MASK;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(xfrm_get_tos);
|
|
+#endif
|
|
+
|
|
static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
|
|
{
|
|
const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
|
|
@@ -3295,6 +3320,37 @@ no_transform:
|
|
dst = dst_orig;
|
|
}
|
|
|
|
+#ifdef IPSEC_FLOW_CACHE
|
|
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
|
|
+ {
|
|
+ struct dst_entry *dst1 = dst;
|
|
+ struct xfrm_state *x;
|
|
+ u16 xfrm_handle[XFRM_POLICY_TYPE_MAX];
|
|
+ u16 ignore_neigh = 0;
|
|
+
|
|
+ num_xfrms = 0;
|
|
+ memset(xfrm_handle, 0, XFRM_POLICY_TYPE_MAX * sizeof(u16));
|
|
+ while (((x = dst1->xfrm) != NULL) &&
|
|
+ (num_xfrms < XFRM_POLICY_TYPE_MAX)) {
|
|
+ xfrm_handle[num_xfrms++] = x->handle;
|
|
+ if (x->props.mode == XFRM_MODE_TUNNEL)
|
|
+ ignore_neigh = 1;
|
|
+ dst1 = xfrm_dst_child(dst1);
|
|
+
|
|
+ if (dst1 == NULL) {
|
|
+ err = -EHOSTUNREACH;
|
|
+ goto error;
|
|
+ }
|
|
+ }
|
|
+ if (ipsec_flow_add(net, fl, family, dir, xfrm_handle)) {
|
|
+ /* sent flow notification to cmm with sa_handle */
|
|
+ ipsec_nlkey_flow(num_xfrms, xfrm_handle, fl, family,
|
|
+ (unsigned short)dir, ignore_neigh);
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+#endif
|
|
+
|
|
ok:
|
|
xfrm_pols_put(pols, drop_pols);
|
|
if (dst->xfrm &&
|
|
@@ -3853,6 +3909,34 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
|
|
goto reject;
|
|
}
|
|
|
|
+#ifdef IPSEC_FLOW_CACHE
|
|
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
|
|
+ {
|
|
+ struct xfrm_state *x;
|
|
+ u16 xfrm_handle[XFRM_POLICY_TYPE_MAX];
|
|
+
|
|
+ xfrm_nr = 0;
|
|
+ memset(xfrm_handle, 0, XFRM_POLICY_TYPE_MAX * sizeof(u16));
|
|
+ for (i = sp->len - 1;
|
|
+ (i >= 0) && (xfrm_nr < XFRM_POLICY_TYPE_MAX); i--) {
|
|
+ x = sp->xvec[i];
|
|
+ xfrm_handle[xfrm_nr++] = x->handle;
|
|
+ }
|
|
+ if (ipsec_flow_add(net, (const struct flowi *)&fl, family, dir,
|
|
+ xfrm_handle)) {
|
|
+ /* sent flow notification to cmm with sa_handle */
|
|
+ ipsec_nlkey_flow(xfrm_nr, xfrm_handle,
|
|
+ (const struct flowi *)&fl, family, dir, 0);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Hub and spoke changes: Setting the POLICY_IN direction in the packet */
|
|
+ skb->ipsec_xfrm_dir |= (1 << XFRM_POLICY_IN);
|
|
+
|
|
+std_path:
|
|
+#endif
|
|
+#endif
|
|
+
|
|
xfrm_pols_put(pols, npols);
|
|
sp->verified_cnt = k;
|
|
|
|
@@ -4328,6 +4412,14 @@ static int __net_init xfrm_net_init(struct net *net)
|
|
if (rv < 0)
|
|
goto out_sysctl;
|
|
|
|
+#ifdef IPSEC_FLOW_CACHE
|
|
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
|
|
+ rv = ipsec_flow_init(net);
|
|
+ if (rv < 0)
|
|
+ goto out_ipsec_flow;
|
|
+#endif
|
|
+#endif
|
|
+
|
|
rv = xfrm_nat_keepalive_net_init(net);
|
|
if (rv < 0)
|
|
goto out_nat_keepalive;
|
|
@@ -4335,6 +4427,12 @@ static int __net_init xfrm_net_init(struct net *net)
|
|
return 0;
|
|
|
|
out_nat_keepalive:
|
|
+#ifdef IPSEC_FLOW_CACHE
|
|
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
|
|
+ ipsec_flow_fini(net);
|
|
+out_ipsec_flow:
|
|
+#endif
|
|
+#endif
|
|
xfrm_sysctl_fini(net);
|
|
out_sysctl:
|
|
xfrm_policy_fini(net);
|
|
@@ -4349,6 +4447,11 @@ out_statistics:
|
|
static void __net_exit xfrm_net_exit(struct net *net)
|
|
{
|
|
xfrm_nat_keepalive_net_fini(net);
|
|
+#ifdef IPSEC_FLOW_CACHE
|
|
+#if defined(CONFIG_INET_IPSEC_OFFLOAD) || defined(CONFIG_INET6_IPSEC_OFFLOAD)
|
|
+ ipsec_flow_fini(net);
|
|
+#endif
|
|
+#endif
|
|
xfrm_sysctl_fini(net);
|
|
xfrm_policy_fini(net);
|
|
xfrm_state_fini(net);
|