|
@@ -1309,15 +1309,28 @@ static inline int xfrm_get_tos(struct flowi *fl, int family)
|
|
return tos;
|
|
return tos;
|
|
}
|
|
}
|
|
|
|
|
|
-static inline struct xfrm_dst *xfrm_alloc_dst(int family)
|
|
|
|
|
|
+static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
|
|
{
|
|
{
|
|
struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
|
|
struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
|
|
|
|
+ struct dst_ops *dst_ops;
|
|
struct xfrm_dst *xdst;
|
|
struct xfrm_dst *xdst;
|
|
|
|
|
|
if (!afinfo)
|
|
if (!afinfo)
|
|
return ERR_PTR(-EINVAL);
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
|
- xdst = dst_alloc(afinfo->dst_ops) ?: ERR_PTR(-ENOBUFS);
|
|
|
|
|
|
+ switch (family) {
|
|
|
|
+ case AF_INET:
|
|
|
|
+ dst_ops = &net->xfrm.xfrm4_dst_ops;
|
|
|
|
+ break;
|
|
|
|
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
|
|
|
+ case AF_INET6:
|
|
|
|
+ dst_ops = &net->xfrm.xfrm6_dst_ops;
|
|
|
|
+ break;
|
|
|
|
+#endif
|
|
|
|
+ default:
|
|
|
|
+ BUG();
|
|
|
|
+ }
|
|
|
|
+ xdst = dst_alloc(dst_ops) ?: ERR_PTR(-ENOBUFS);
|
|
|
|
|
|
xfrm_policy_put_afinfo(afinfo);
|
|
xfrm_policy_put_afinfo(afinfo);
|
|
|
|
|
|
@@ -1366,6 +1379,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
|
|
struct flowi *fl,
|
|
struct flowi *fl,
|
|
struct dst_entry *dst)
|
|
struct dst_entry *dst)
|
|
{
|
|
{
|
|
|
|
+ struct net *net = xp_net(policy);
|
|
unsigned long now = jiffies;
|
|
unsigned long now = jiffies;
|
|
struct net_device *dev;
|
|
struct net_device *dev;
|
|
struct dst_entry *dst_prev = NULL;
|
|
struct dst_entry *dst_prev = NULL;
|
|
@@ -1389,7 +1403,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
|
|
dst_hold(dst);
|
|
dst_hold(dst);
|
|
|
|
|
|
for (; i < nx; i++) {
|
|
for (; i < nx; i++) {
|
|
- struct xfrm_dst *xdst = xfrm_alloc_dst(family);
|
|
|
|
|
|
+ struct xfrm_dst *xdst = xfrm_alloc_dst(net, family);
|
|
struct dst_entry *dst1 = &xdst->u.dst;
|
|
struct dst_entry *dst1 = &xdst->u.dst;
|
|
|
|
|
|
err = PTR_ERR(xdst);
|
|
err = PTR_ERR(xdst);
|
|
@@ -2279,6 +2293,7 @@ EXPORT_SYMBOL(xfrm_bundle_ok);
|
|
|
|
|
|
int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
|
|
int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
|
|
{
|
|
{
|
|
|
|
+ struct net *net;
|
|
int err = 0;
|
|
int err = 0;
|
|
if (unlikely(afinfo == NULL))
|
|
if (unlikely(afinfo == NULL))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
@@ -2302,6 +2317,27 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
|
|
xfrm_policy_afinfo[afinfo->family] = afinfo;
|
|
xfrm_policy_afinfo[afinfo->family] = afinfo;
|
|
}
|
|
}
|
|
write_unlock_bh(&xfrm_policy_afinfo_lock);
|
|
write_unlock_bh(&xfrm_policy_afinfo_lock);
|
|
|
|
+
|
|
|
|
+ rtnl_lock();
|
|
|
|
+ for_each_net(net) {
|
|
|
|
+ struct dst_ops *xfrm_dst_ops;
|
|
|
|
+
|
|
|
|
+ switch (afinfo->family) {
|
|
|
|
+ case AF_INET:
|
|
|
|
+ xfrm_dst_ops = &net->xfrm.xfrm4_dst_ops;
|
|
|
|
+ break;
|
|
|
|
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
|
|
|
+ case AF_INET6:
|
|
|
|
+ xfrm_dst_ops = &net->xfrm.xfrm6_dst_ops;
|
|
|
|
+ break;
|
|
|
|
+#endif
|
|
|
|
+ default:
|
|
|
|
+ BUG();
|
|
|
|
+ }
|
|
|
|
+ *xfrm_dst_ops = *afinfo->dst_ops;
|
|
|
|
+ }
|
|
|
|
+ rtnl_unlock();
|
|
|
|
+
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(xfrm_policy_register_afinfo);
|
|
EXPORT_SYMBOL(xfrm_policy_register_afinfo);
|
|
@@ -2332,6 +2368,22 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);
|
|
EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);
|
|
|
|
|
|
|
|
+static void __net_init xfrm_dst_ops_init(struct net *net)
|
|
|
|
+{
|
|
|
|
+ struct xfrm_policy_afinfo *afinfo;
|
|
|
|
+
|
|
|
|
+ read_lock_bh(&xfrm_policy_afinfo_lock);
|
|
|
|
+ afinfo = xfrm_policy_afinfo[AF_INET];
|
|
|
|
+ if (afinfo)
|
|
|
|
+ net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops;
|
|
|
|
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
|
|
|
+ afinfo = xfrm_policy_afinfo[AF_INET6];
|
|
|
|
+ if (afinfo)
|
|
|
|
+ net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops;
|
|
|
|
+#endif
|
|
|
|
+ read_unlock_bh(&xfrm_policy_afinfo_lock);
|
|
|
|
+}
|
|
|
|
+
|
|
static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
|
|
static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
|
|
{
|
|
{
|
|
struct xfrm_policy_afinfo *afinfo;
|
|
struct xfrm_policy_afinfo *afinfo;
|
|
@@ -2494,6 +2546,7 @@ static int __net_init xfrm_net_init(struct net *net)
|
|
rv = xfrm_policy_init(net);
|
|
rv = xfrm_policy_init(net);
|
|
if (rv < 0)
|
|
if (rv < 0)
|
|
goto out_policy;
|
|
goto out_policy;
|
|
|
|
+ xfrm_dst_ops_init(net);
|
|
rv = xfrm_sysctl_init(net);
|
|
rv = xfrm_sysctl_init(net);
|
|
if (rv < 0)
|
|
if (rv < 0)
|
|
goto out_sysctl;
|
|
goto out_sysctl;
|