|
@@ -60,41 +60,6 @@ struct pcpu_dstats {
|
|
|
struct u64_stats_sync syncp;
|
|
|
};
|
|
|
|
|
|
-static struct dst_entry *vrf_ip_check(struct dst_entry *dst, u32 cookie)
|
|
|
-{
|
|
|
- return dst;
|
|
|
-}
|
|
|
-
|
|
|
-static int vrf_ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
|
|
|
-{
|
|
|
- return ip_local_out(net, sk, skb);
|
|
|
-}
|
|
|
-
|
|
|
-static unsigned int vrf_v4_mtu(const struct dst_entry *dst)
|
|
|
-{
|
|
|
- /* TO-DO: return max ethernet size? */
|
|
|
- return dst->dev->mtu;
|
|
|
-}
|
|
|
-
|
|
|
-static void vrf_dst_destroy(struct dst_entry *dst)
|
|
|
-{
|
|
|
- /* our dst lives forever - or until the device is closed */
|
|
|
-}
|
|
|
-
|
|
|
-static unsigned int vrf_default_advmss(const struct dst_entry *dst)
|
|
|
-{
|
|
|
- return 65535 - 40;
|
|
|
-}
|
|
|
-
|
|
|
-static struct dst_ops vrf_dst_ops = {
|
|
|
- .family = AF_INET,
|
|
|
- .local_out = vrf_ip_local_out,
|
|
|
- .check = vrf_ip_check,
|
|
|
- .mtu = vrf_v4_mtu,
|
|
|
- .destroy = vrf_dst_destroy,
|
|
|
- .default_advmss = vrf_default_advmss,
|
|
|
-};
|
|
|
-
|
|
|
/* neighbor handling is done with actual device; do not want
|
|
|
* to flip skb->dev for those ndisc packets. This really fails
|
|
|
* for multiple next protocols (e.g., NEXTHDR_HOP). But it is
|
|
@@ -349,46 +314,6 @@ static netdev_tx_t vrf_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
|
}
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
|
-static struct dst_entry *vrf_ip6_check(struct dst_entry *dst, u32 cookie)
|
|
|
-{
|
|
|
- return dst;
|
|
|
-}
|
|
|
-
|
|
|
-static struct dst_ops vrf_dst_ops6 = {
|
|
|
- .family = AF_INET6,
|
|
|
- .local_out = ip6_local_out,
|
|
|
- .check = vrf_ip6_check,
|
|
|
- .mtu = vrf_v4_mtu,
|
|
|
- .destroy = vrf_dst_destroy,
|
|
|
- .default_advmss = vrf_default_advmss,
|
|
|
-};
|
|
|
-
|
|
|
-static int init_dst_ops6_kmem_cachep(void)
|
|
|
-{
|
|
|
- vrf_dst_ops6.kmem_cachep = kmem_cache_create("vrf_ip6_dst_cache",
|
|
|
- sizeof(struct rt6_info),
|
|
|
- 0,
|
|
|
- SLAB_HWCACHE_ALIGN,
|
|
|
- NULL);
|
|
|
-
|
|
|
- if (!vrf_dst_ops6.kmem_cachep)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void free_dst_ops6_kmem_cachep(void)
|
|
|
-{
|
|
|
- kmem_cache_destroy(vrf_dst_ops6.kmem_cachep);
|
|
|
-}
|
|
|
-
|
|
|
-static int vrf_input6(struct sk_buff *skb)
|
|
|
-{
|
|
|
- skb->dev->stats.rx_errors++;
|
|
|
- kfree_skb(skb);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
/* modelled after ip6_finish_output2 */
|
|
|
static int vrf_finish_output6(struct net *net, struct sock *sk,
|
|
|
struct sk_buff *skb)
|
|
@@ -429,67 +354,34 @@ static int vrf_output6(struct net *net, struct sock *sk, struct sk_buff *skb)
|
|
|
!(IP6CB(skb)->flags & IP6SKB_REROUTED));
|
|
|
}
|
|
|
|
|
|
-static void vrf_rt6_destroy(struct net_vrf *vrf)
|
|
|
+static void vrf_rt6_release(struct net_vrf *vrf)
|
|
|
{
|
|
|
- dst_destroy(&vrf->rt6->dst);
|
|
|
- free_percpu(vrf->rt6->rt6i_pcpu);
|
|
|
+ dst_release(&vrf->rt6->dst);
|
|
|
vrf->rt6 = NULL;
|
|
|
}
|
|
|
|
|
|
static int vrf_rt6_create(struct net_device *dev)
|
|
|
{
|
|
|
struct net_vrf *vrf = netdev_priv(dev);
|
|
|
- struct dst_entry *dst;
|
|
|
+ struct net *net = dev_net(dev);
|
|
|
struct rt6_info *rt6;
|
|
|
- int cpu;
|
|
|
int rc = -ENOMEM;
|
|
|
|
|
|
- rt6 = dst_alloc(&vrf_dst_ops6, dev, 0,
|
|
|
- DST_OBSOLETE_NONE,
|
|
|
- (DST_HOST | DST_NOPOLICY | DST_NOXFRM));
|
|
|
+ rt6 = ip6_dst_alloc(net, dev,
|
|
|
+ DST_HOST | DST_NOPOLICY | DST_NOXFRM | DST_NOCACHE);
|
|
|
if (!rt6)
|
|
|
goto out;
|
|
|
|
|
|
- dst = &rt6->dst;
|
|
|
-
|
|
|
- rt6->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_KERNEL);
|
|
|
- if (!rt6->rt6i_pcpu) {
|
|
|
- dst_destroy(dst);
|
|
|
- goto out;
|
|
|
- }
|
|
|
- for_each_possible_cpu(cpu) {
|
|
|
- struct rt6_info **p = per_cpu_ptr(rt6->rt6i_pcpu, cpu);
|
|
|
- *p = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- memset(dst + 1, 0, sizeof(*rt6) - sizeof(*dst));
|
|
|
-
|
|
|
- INIT_LIST_HEAD(&rt6->rt6i_siblings);
|
|
|
- INIT_LIST_HEAD(&rt6->rt6i_uncached);
|
|
|
-
|
|
|
- rt6->dst.input = vrf_input6;
|
|
|
rt6->dst.output = vrf_output6;
|
|
|
-
|
|
|
- rt6->rt6i_table = fib6_get_table(dev_net(dev), vrf->tb_id);
|
|
|
-
|
|
|
- atomic_set(&rt6->dst.__refcnt, 2);
|
|
|
-
|
|
|
+ rt6->rt6i_table = fib6_get_table(net, vrf->tb_id);
|
|
|
+ dst_hold(&rt6->dst);
|
|
|
vrf->rt6 = rt6;
|
|
|
rc = 0;
|
|
|
out:
|
|
|
return rc;
|
|
|
}
|
|
|
#else
|
|
|
-static int init_dst_ops6_kmem_cachep(void)
|
|
|
-{
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void free_dst_ops6_kmem_cachep(void)
|
|
|
-{
|
|
|
-}
|
|
|
-
|
|
|
-static void vrf_rt6_destroy(struct net_vrf *vrf)
|
|
|
+static void vrf_rt6_release(struct net_vrf *vrf)
|
|
|
{
|
|
|
}
|
|
|
|
|
@@ -557,11 +449,11 @@ static int vrf_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
|
|
!(IPCB(skb)->flags & IPSKB_REROUTED));
|
|
|
}
|
|
|
|
|
|
-static void vrf_rtable_destroy(struct net_vrf *vrf)
|
|
|
+static void vrf_rtable_release(struct net_vrf *vrf)
|
|
|
{
|
|
|
struct dst_entry *dst = (struct dst_entry *)vrf->rth;
|
|
|
|
|
|
- dst_destroy(dst);
|
|
|
+ dst_release(dst);
|
|
|
vrf->rth = NULL;
|
|
|
}
|
|
|
|
|
@@ -570,22 +462,10 @@ static struct rtable *vrf_rtable_create(struct net_device *dev)
|
|
|
struct net_vrf *vrf = netdev_priv(dev);
|
|
|
struct rtable *rth;
|
|
|
|
|
|
- rth = dst_alloc(&vrf_dst_ops, dev, 2,
|
|
|
- DST_OBSOLETE_NONE,
|
|
|
- (DST_HOST | DST_NOPOLICY | DST_NOXFRM));
|
|
|
+ rth = rt_dst_alloc(dev, 0, RTN_UNICAST, 1, 1, 0);
|
|
|
if (rth) {
|
|
|
rth->dst.output = vrf_output;
|
|
|
- rth->rt_genid = rt_genid_ipv4(dev_net(dev));
|
|
|
- rth->rt_flags = 0;
|
|
|
- rth->rt_type = RTN_UNICAST;
|
|
|
- rth->rt_is_input = 0;
|
|
|
- rth->rt_iif = 0;
|
|
|
- rth->rt_pmtu = 0;
|
|
|
- rth->rt_gateway = 0;
|
|
|
- rth->rt_uses_gateway = 0;
|
|
|
rth->rt_table_id = vrf->tb_id;
|
|
|
- INIT_LIST_HEAD(&rth->rt_uncached);
|
|
|
- rth->rt_uncached_list = NULL;
|
|
|
}
|
|
|
|
|
|
return rth;
|
|
@@ -673,8 +553,8 @@ static void vrf_dev_uninit(struct net_device *dev)
|
|
|
struct net_device *port_dev;
|
|
|
struct list_head *iter;
|
|
|
|
|
|
- vrf_rtable_destroy(vrf);
|
|
|
- vrf_rt6_destroy(vrf);
|
|
|
+ vrf_rtable_release(vrf);
|
|
|
+ vrf_rt6_release(vrf);
|
|
|
|
|
|
netdev_for_each_lower_dev(dev, port_dev, iter)
|
|
|
vrf_del_slave(dev, port_dev);
|
|
@@ -704,7 +584,7 @@ static int vrf_dev_init(struct net_device *dev)
|
|
|
return 0;
|
|
|
|
|
|
out_rth:
|
|
|
- vrf_rtable_destroy(vrf);
|
|
|
+ vrf_rtable_release(vrf);
|
|
|
out_stats:
|
|
|
free_percpu(dev->dstats);
|
|
|
dev->dstats = NULL;
|
|
@@ -737,7 +617,7 @@ static struct rtable *vrf_get_rtable(const struct net_device *dev,
|
|
|
struct net_vrf *vrf = netdev_priv(dev);
|
|
|
|
|
|
rth = vrf->rth;
|
|
|
- atomic_inc(&rth->dst.__refcnt);
|
|
|
+ dst_hold(&rth->dst);
|
|
|
}
|
|
|
|
|
|
return rth;
|
|
@@ -788,7 +668,7 @@ static struct dst_entry *vrf_get_rt6_dst(const struct net_device *dev,
|
|
|
struct net_vrf *vrf = netdev_priv(dev);
|
|
|
|
|
|
rt = vrf->rt6;
|
|
|
- atomic_inc(&rt->dst.__refcnt);
|
|
|
+ dst_hold(&rt->dst);
|
|
|
}
|
|
|
|
|
|
return (struct dst_entry *)rt;
|
|
@@ -946,19 +826,6 @@ static int __init vrf_init_module(void)
|
|
|
{
|
|
|
int rc;
|
|
|
|
|
|
- vrf_dst_ops.kmem_cachep =
|
|
|
- kmem_cache_create("vrf_ip_dst_cache",
|
|
|
- sizeof(struct rtable), 0,
|
|
|
- SLAB_HWCACHE_ALIGN,
|
|
|
- NULL);
|
|
|
-
|
|
|
- if (!vrf_dst_ops.kmem_cachep)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- rc = init_dst_ops6_kmem_cachep();
|
|
|
- if (rc != 0)
|
|
|
- goto error2;
|
|
|
-
|
|
|
register_netdevice_notifier(&vrf_notifier_block);
|
|
|
|
|
|
rc = rtnl_link_register(&vrf_link_ops);
|
|
@@ -969,22 +836,10 @@ static int __init vrf_init_module(void)
|
|
|
|
|
|
error:
|
|
|
unregister_netdevice_notifier(&vrf_notifier_block);
|
|
|
- free_dst_ops6_kmem_cachep();
|
|
|
-error2:
|
|
|
- kmem_cache_destroy(vrf_dst_ops.kmem_cachep);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-static void __exit vrf_cleanup_module(void)
|
|
|
-{
|
|
|
- rtnl_link_unregister(&vrf_link_ops);
|
|
|
- unregister_netdevice_notifier(&vrf_notifier_block);
|
|
|
- kmem_cache_destroy(vrf_dst_ops.kmem_cachep);
|
|
|
- free_dst_ops6_kmem_cachep();
|
|
|
-}
|
|
|
-
|
|
|
module_init(vrf_init_module);
|
|
|
-module_exit(vrf_cleanup_module);
|
|
|
MODULE_AUTHOR("Shrijeet Mukherjee, David Ahern");
|
|
|
MODULE_DESCRIPTION("Device driver to instantiate VRF domains");
|
|
|
MODULE_LICENSE("GPL");
|