net: Revert vrf-local changes.
This reverts commit 2fb7ea455d
.
It results in build errors because ip6_input is not a
symbol exported to modules.
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
2fb7ea455d
commit
3d9dc408fa
|
@ -44,9 +44,7 @@
|
||||||
|
|
||||||
struct net_vrf {
|
struct net_vrf {
|
||||||
struct rtable __rcu *rth;
|
struct rtable __rcu *rth;
|
||||||
struct rtable __rcu *rth_local;
|
|
||||||
struct rt6_info __rcu *rt6;
|
struct rt6_info __rcu *rt6;
|
||||||
struct rt6_info __rcu *rt6_local;
|
|
||||||
u32 tb_id;
|
u32 tb_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,20 +54,9 @@ struct pcpu_dstats {
|
||||||
u64 tx_drps;
|
u64 tx_drps;
|
||||||
u64 rx_pkts;
|
u64 rx_pkts;
|
||||||
u64 rx_bytes;
|
u64 rx_bytes;
|
||||||
u64 rx_drps;
|
|
||||||
struct u64_stats_sync syncp;
|
struct u64_stats_sync syncp;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void vrf_rx_stats(struct net_device *dev, int len)
|
|
||||||
{
|
|
||||||
struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
|
|
||||||
|
|
||||||
u64_stats_update_begin(&dstats->syncp);
|
|
||||||
dstats->rx_pkts++;
|
|
||||||
dstats->rx_bytes += len;
|
|
||||||
u64_stats_update_end(&dstats->syncp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vrf_tx_error(struct net_device *vrf_dev, struct sk_buff *skb)
|
static void vrf_tx_error(struct net_device *vrf_dev, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
vrf_dev->stats.tx_errors++;
|
vrf_dev->stats.tx_errors++;
|
||||||
|
@ -104,34 +91,6 @@ static struct rtnl_link_stats64 *vrf_get_stats64(struct net_device *dev,
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Local traffic destined to local address. Reinsert the packet to rx
|
|
||||||
* path, similar to loopback handling.
|
|
||||||
*/
|
|
||||||
static int vrf_local_xmit(struct sk_buff *skb, struct net_device *dev,
|
|
||||||
struct dst_entry *dst)
|
|
||||||
{
|
|
||||||
int len = skb->len;
|
|
||||||
|
|
||||||
skb_orphan(skb);
|
|
||||||
|
|
||||||
skb_dst_set(skb, dst);
|
|
||||||
skb_dst_force(skb);
|
|
||||||
|
|
||||||
/* set pkt_type to avoid skb hitting packet taps twice -
|
|
||||||
* once on Tx and again in Rx processing
|
|
||||||
*/
|
|
||||||
skb->pkt_type = PACKET_LOOPBACK;
|
|
||||||
|
|
||||||
skb->protocol = eth_type_trans(skb, dev);
|
|
||||||
|
|
||||||
if (likely(netif_rx(skb) == NET_RX_SUCCESS))
|
|
||||||
vrf_rx_stats(dev, len);
|
|
||||||
else
|
|
||||||
this_cpu_inc(dev->dstats->rx_drps);
|
|
||||||
|
|
||||||
return NETDEV_TX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
|
static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
|
||||||
struct net_device *dev)
|
struct net_device *dev)
|
||||||
|
@ -158,51 +117,8 @@ static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
skb_dst_drop(skb);
|
skb_dst_drop(skb);
|
||||||
|
|
||||||
/* if dst.dev is loopback or the VRF device again this is locally
|
|
||||||
* originated traffic destined to a local address. Short circuit
|
|
||||||
* to Rx path using our local dst
|
|
||||||
*/
|
|
||||||
if (dst->dev == net->loopback_dev || dst->dev == dev) {
|
|
||||||
struct net_vrf *vrf = netdev_priv(dev);
|
|
||||||
struct rt6_info *rt6_local;
|
|
||||||
|
|
||||||
/* release looked up dst and use cached local dst */
|
|
||||||
dst_release(dst);
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
rt6_local = rcu_dereference(vrf->rt6_local);
|
|
||||||
if (unlikely(!rt6_local)) {
|
|
||||||
rcu_read_unlock();
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ordering issue: cached local dst is created on newlink
|
|
||||||
* before the IPv6 initialization. Using the local dst
|
|
||||||
* requires rt6i_idev to be set so make sure it is.
|
|
||||||
*/
|
|
||||||
if (unlikely(!rt6_local->rt6i_idev)) {
|
|
||||||
rt6_local->rt6i_idev = in6_dev_get(dev);
|
|
||||||
if (!rt6_local->rt6i_idev) {
|
|
||||||
rcu_read_unlock();
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dst = &rt6_local->dst;
|
|
||||||
dst_hold(dst);
|
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
return vrf_local_xmit(skb, dev, &rt6_local->dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
skb_dst_set(skb, dst);
|
skb_dst_set(skb, dst);
|
||||||
|
|
||||||
/* strip the ethernet header added for pass through VRF device */
|
|
||||||
__skb_pull(skb, skb_network_offset(skb));
|
|
||||||
|
|
||||||
ret = ip6_local_out(net, skb->sk, skb);
|
ret = ip6_local_out(net, skb->sk, skb);
|
||||||
if (unlikely(net_xmit_eval(ret)))
|
if (unlikely(net_xmit_eval(ret)))
|
||||||
dev->stats.tx_errors++;
|
dev->stats.tx_errors++;
|
||||||
|
@ -223,6 +139,29 @@ static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int vrf_send_v4_prep(struct sk_buff *skb, struct flowi4 *fl4,
|
||||||
|
struct net_device *vrf_dev)
|
||||||
|
{
|
||||||
|
struct rtable *rt;
|
||||||
|
int err = 1;
|
||||||
|
|
||||||
|
rt = ip_route_output_flow(dev_net(vrf_dev), fl4, NULL);
|
||||||
|
if (IS_ERR(rt))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* TO-DO: what about broadcast ? */
|
||||||
|
if (rt->rt_type != RTN_UNICAST && rt->rt_type != RTN_LOCAL) {
|
||||||
|
ip_rt_put(rt);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
skb_dst_drop(skb);
|
||||||
|
skb_dst_set(skb, &rt->dst);
|
||||||
|
err = 0;
|
||||||
|
out:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb,
|
static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb,
|
||||||
struct net_device *vrf_dev)
|
struct net_device *vrf_dev)
|
||||||
{
|
{
|
||||||
|
@ -237,52 +176,10 @@ static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb,
|
||||||
FLOWI_FLAG_SKIP_NH_OIF,
|
FLOWI_FLAG_SKIP_NH_OIF,
|
||||||
.daddr = ip4h->daddr,
|
.daddr = ip4h->daddr,
|
||||||
};
|
};
|
||||||
struct net *net = dev_net(vrf_dev);
|
|
||||||
struct rtable *rt;
|
|
||||||
|
|
||||||
rt = ip_route_output_flow(net, &fl4, NULL);
|
if (vrf_send_v4_prep(skb, &fl4, vrf_dev))
|
||||||
if (IS_ERR(rt))
|
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (rt->rt_type != RTN_UNICAST && rt->rt_type != RTN_LOCAL) {
|
|
||||||
ip_rt_put(rt);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
skb_dst_drop(skb);
|
|
||||||
|
|
||||||
/* if dst.dev is loopback or the VRF device again this is locally
|
|
||||||
* originated traffic destined to a local address. Short circuit
|
|
||||||
* to Rx path using our local dst
|
|
||||||
*/
|
|
||||||
if (rt->dst.dev == net->loopback_dev || rt->dst.dev == vrf_dev) {
|
|
||||||
struct net_vrf *vrf = netdev_priv(vrf_dev);
|
|
||||||
struct rtable *rth_local;
|
|
||||||
struct dst_entry *dst = NULL;
|
|
||||||
|
|
||||||
ip_rt_put(rt);
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
rth_local = rcu_dereference(vrf->rth_local);
|
|
||||||
if (likely(rth_local)) {
|
|
||||||
dst = &rth_local->dst;
|
|
||||||
dst_hold(dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if (unlikely(!dst))
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
return vrf_local_xmit(skb, vrf_dev, dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
skb_dst_set(skb, &rt->dst);
|
|
||||||
|
|
||||||
/* strip the ethernet header added for pass through VRF device */
|
|
||||||
__skb_pull(skb, skb_network_offset(skb));
|
|
||||||
|
|
||||||
if (!ip4h->saddr) {
|
if (!ip4h->saddr) {
|
||||||
ip4h->saddr = inet_select_addr(skb_dst(skb)->dev, 0,
|
ip4h->saddr = inet_select_addr(skb_dst(skb)->dev, 0,
|
||||||
RT_SCOPE_LINK);
|
RT_SCOPE_LINK);
|
||||||
|
@ -303,6 +200,9 @@ err:
|
||||||
|
|
||||||
static netdev_tx_t is_ip_tx_frame(struct sk_buff *skb, struct net_device *dev)
|
static netdev_tx_t is_ip_tx_frame(struct sk_buff *skb, struct net_device *dev)
|
||||||
{
|
{
|
||||||
|
/* strip the ethernet header added for pass through VRF device */
|
||||||
|
__skb_pull(skb, skb_network_offset(skb));
|
||||||
|
|
||||||
switch (skb->protocol) {
|
switch (skb->protocol) {
|
||||||
case htons(ETH_P_IP):
|
case htons(ETH_P_IP):
|
||||||
return vrf_process_v4_outbound(skb, dev);
|
return vrf_process_v4_outbound(skb, dev);
|
||||||
|
@ -377,38 +277,27 @@ static int vrf_output6(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||||
static void vrf_rt6_release(struct net_vrf *vrf)
|
static void vrf_rt6_release(struct net_vrf *vrf)
|
||||||
{
|
{
|
||||||
struct rt6_info *rt6 = rtnl_dereference(vrf->rt6);
|
struct rt6_info *rt6 = rtnl_dereference(vrf->rt6);
|
||||||
struct rt6_info *rt6_local = rtnl_dereference(vrf->rt6_local);
|
|
||||||
|
|
||||||
RCU_INIT_POINTER(vrf->rt6, NULL);
|
rcu_assign_pointer(vrf->rt6, NULL);
|
||||||
RCU_INIT_POINTER(vrf->rt6_local, NULL);
|
|
||||||
synchronize_rcu();
|
|
||||||
|
|
||||||
if (rt6)
|
if (rt6)
|
||||||
dst_release(&rt6->dst);
|
dst_release(&rt6->dst);
|
||||||
|
|
||||||
if (rt6_local) {
|
|
||||||
if (rt6_local->rt6i_idev)
|
|
||||||
in6_dev_put(rt6_local->rt6i_idev);
|
|
||||||
|
|
||||||
dst_release(&rt6_local->dst);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vrf_rt6_create(struct net_device *dev)
|
static int vrf_rt6_create(struct net_device *dev)
|
||||||
{
|
{
|
||||||
int flags = DST_HOST | DST_NOPOLICY | DST_NOXFRM | DST_NOCACHE;
|
|
||||||
struct net_vrf *vrf = netdev_priv(dev);
|
struct net_vrf *vrf = netdev_priv(dev);
|
||||||
struct net *net = dev_net(dev);
|
struct net *net = dev_net(dev);
|
||||||
struct fib6_table *rt6i_table;
|
struct fib6_table *rt6i_table;
|
||||||
struct rt6_info *rt6, *rt6_local;
|
struct rt6_info *rt6;
|
||||||
int rc = -ENOMEM;
|
int rc = -ENOMEM;
|
||||||
|
|
||||||
rt6i_table = fib6_new_table(net, vrf->tb_id);
|
rt6i_table = fib6_new_table(net, vrf->tb_id);
|
||||||
if (!rt6i_table)
|
if (!rt6i_table)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* create a dst for routing packets out a VRF device */
|
rt6 = ip6_dst_alloc(net, dev,
|
||||||
rt6 = ip6_dst_alloc(net, dev, flags);
|
DST_HOST | DST_NOPOLICY | DST_NOXFRM | DST_NOCACHE);
|
||||||
if (!rt6)
|
if (!rt6)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -416,25 +305,7 @@ static int vrf_rt6_create(struct net_device *dev)
|
||||||
|
|
||||||
rt6->rt6i_table = rt6i_table;
|
rt6->rt6i_table = rt6i_table;
|
||||||
rt6->dst.output = vrf_output6;
|
rt6->dst.output = vrf_output6;
|
||||||
|
|
||||||
/* create a dst for local routing - packets sent locally
|
|
||||||
* to local address via the VRF device as a loopback
|
|
||||||
*/
|
|
||||||
rt6_local = ip6_dst_alloc(net, dev, flags);
|
|
||||||
if (!rt6_local) {
|
|
||||||
dst_release(&rt6->dst);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
dst_hold(&rt6_local->dst);
|
|
||||||
|
|
||||||
rt6_local->rt6i_idev = in6_dev_get(dev);
|
|
||||||
rt6_local->rt6i_flags = RTF_UP | RTF_NONEXTHOP | RTF_LOCAL;
|
|
||||||
rt6_local->rt6i_table = rt6i_table;
|
|
||||||
rt6_local->dst.input = ip6_input;
|
|
||||||
|
|
||||||
rcu_assign_pointer(vrf->rt6, rt6);
|
rcu_assign_pointer(vrf->rt6, rt6);
|
||||||
rcu_assign_pointer(vrf->rt6_local, rt6_local);
|
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
out:
|
out:
|
||||||
|
@ -513,48 +384,29 @@ static int vrf_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||||
static void vrf_rtable_release(struct net_vrf *vrf)
|
static void vrf_rtable_release(struct net_vrf *vrf)
|
||||||
{
|
{
|
||||||
struct rtable *rth = rtnl_dereference(vrf->rth);
|
struct rtable *rth = rtnl_dereference(vrf->rth);
|
||||||
struct rtable *rth_local = rtnl_dereference(vrf->rth_local);
|
|
||||||
|
|
||||||
RCU_INIT_POINTER(vrf->rth, NULL);
|
rcu_assign_pointer(vrf->rth, NULL);
|
||||||
RCU_INIT_POINTER(vrf->rth_local, NULL);
|
|
||||||
synchronize_rcu();
|
|
||||||
|
|
||||||
if (rth)
|
if (rth)
|
||||||
dst_release(&rth->dst);
|
dst_release(&rth->dst);
|
||||||
|
|
||||||
if (rth_local)
|
|
||||||
dst_release(&rth_local->dst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vrf_rtable_create(struct net_device *dev)
|
static int vrf_rtable_create(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct net_vrf *vrf = netdev_priv(dev);
|
struct net_vrf *vrf = netdev_priv(dev);
|
||||||
struct rtable *rth, *rth_local;
|
struct rtable *rth;
|
||||||
|
|
||||||
if (!fib_new_table(dev_net(dev), vrf->tb_id))
|
if (!fib_new_table(dev_net(dev), vrf->tb_id))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* create a dst for routing packets out through a VRF device */
|
|
||||||
rth = rt_dst_alloc(dev, 0, RTN_UNICAST, 1, 1, 0);
|
rth = rt_dst_alloc(dev, 0, RTN_UNICAST, 1, 1, 0);
|
||||||
if (!rth)
|
if (!rth)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* create a dst for local ingress routing - packets sent locally
|
|
||||||
* to local address via the VRF device as a loopback
|
|
||||||
*/
|
|
||||||
rth_local = rt_dst_alloc(dev, RTCF_LOCAL, RTN_LOCAL, 1, 1, 0);
|
|
||||||
if (!rth_local) {
|
|
||||||
dst_release(&rth->dst);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
rth->dst.output = vrf_output;
|
rth->dst.output = vrf_output;
|
||||||
rth->rt_table_id = vrf->tb_id;
|
rth->rt_table_id = vrf->tb_id;
|
||||||
|
|
||||||
rth_local->rt_table_id = vrf->tb_id;
|
|
||||||
|
|
||||||
rcu_assign_pointer(vrf->rth, rth);
|
rcu_assign_pointer(vrf->rth, rth);
|
||||||
rcu_assign_pointer(vrf->rth_local, rth_local);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -780,16 +632,6 @@ out:
|
||||||
static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev,
|
static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
/* loopback traffic; do not push through packet taps again.
|
|
||||||
* Reset pkt_type for upper layers to process skb
|
|
||||||
*/
|
|
||||||
if (skb->pkt_type == PACKET_LOOPBACK) {
|
|
||||||
skb->dev = vrf_dev;
|
|
||||||
skb->skb_iif = vrf_dev->ifindex;
|
|
||||||
skb->pkt_type = PACKET_HOST;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if packet is NDISC keep the ingress interface */
|
/* if packet is NDISC keep the ingress interface */
|
||||||
if (!ipv6_ndisc_frame(skb)) {
|
if (!ipv6_ndisc_frame(skb)) {
|
||||||
skb->dev = vrf_dev;
|
skb->dev = vrf_dev;
|
||||||
|
@ -802,7 +644,6 @@ static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev,
|
||||||
IP6CB(skb)->flags |= IP6SKB_L3SLAVE;
|
IP6CB(skb)->flags |= IP6SKB_L3SLAVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -820,19 +661,10 @@ static struct sk_buff *vrf_ip_rcv(struct net_device *vrf_dev,
|
||||||
skb->dev = vrf_dev;
|
skb->dev = vrf_dev;
|
||||||
skb->skb_iif = vrf_dev->ifindex;
|
skb->skb_iif = vrf_dev->ifindex;
|
||||||
|
|
||||||
/* loopback traffic; do not push through packet taps again.
|
|
||||||
* Reset pkt_type for upper layers to process skb
|
|
||||||
*/
|
|
||||||
if (skb->pkt_type == PACKET_LOOPBACK) {
|
|
||||||
skb->pkt_type = PACKET_HOST;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
skb_push(skb, skb->mac_len);
|
skb_push(skb, skb->mac_len);
|
||||||
dev_queue_xmit_nit(skb, vrf_dev);
|
dev_queue_xmit_nit(skb, vrf_dev);
|
||||||
skb_pull(skb, skb->mac_len);
|
skb_pull(skb, skb->mac_len);
|
||||||
|
|
||||||
out:
|
|
||||||
return skb;
|
return skb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue