From: David Ahern <hidden> Date: 2016-06-02 20:16:41
Add support for locally originated traffic to VRF-local addresses,
be it addresses on enslaved devices or addresses on the VRF device:
$ ip addr show dev red
33: red: <NOARP,MASTER,UP,LOWER_UP> mtu 65536 qdisc pfifo_fast state UP group default qlen 1000
link/ether be:00:53:b5:e4:25 brd ff:ff:ff:ff:ff:ff
inet 1.1.1.1/32 scope global red
valid_lft forever preferred_lft forever
inet6 1111:1::1/128 scope global
valid_lft forever preferred_lft forever
$ ip addr show dev eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master red state UP group default qlen 1000
link/ether 02:e0:f9:79:34:bd brd ff:ff:ff:ff:ff:ff
inet 10.100.1.1/24 brd 10.100.1.255 scope global eth1
valid_lft forever preferred_lft forever
inet6 2100:1::1/120 scope global
valid_lft forever preferred_lft forever
inet6 fe80::e0:f9ff:fe79:34bd/64 scope link
valid_lft forever preferred_lft forever
$ ping -c1 -I red 10.100.1.1
ping: Warning: source address might be selected on device other than red.
PING 10.100.1.1 (10.100.1.1) from 10.100.1.1 red: 56(84) bytes of data.
64 bytes from 10.100.1.1: icmp_seq=1 ttl=64 time=0.057 ms
$ ping -c1 -I red 1.1.1.1
PING 1.1.1.1 (1.1.1.1) from 1.1.1.1 red: 56(84) bytes of data.
64 bytes from 1.1.1.1: icmp_seq=1 ttl=64 time=0.136 ms
--- 1.1.1.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.136/0.136/0.136/0.000 ms
$ ping6 -c1 -I red 2100:1::1
ping6: Warning: source address might be selected on device other than red.
PING 2100:1::1(2100:1::1) from 2100:1::1 red: 56 data bytes
64 bytes from 2100:1::1: icmp_seq=1 ttl=64 time=0.167 ms
--- 2100:1::1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.167/0.167/0.167/0.000 ms
$ ping6 -c1 -I red 1111::1
PING 1111::1(1111::1) from 1111:1::1 red: 56 data bytes
64 bytes from 1111::1: icmp_seq=1 ttl=64 time=0.187 ms
--- 1111::1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.187/0.187/0.187/0.000 ms
This change also enables use of loopback address on the VRF device:
$ ip addr add dev red 127.0.0.1/8
$ ping -c1 -I red 127.0.0.1
PING 127.0.0.1 (127.0.0.1) from 127.0.0.1 red: 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.058 ms
David Ahern (3):
net: vrf: Minor refactoring for local address patches
net: vrf: ipv4 support for local traffic to local addresses
net: vrf: ipv6 support for local traffic to local addresses
drivers/net/vrf.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 201 insertions(+), 33 deletions(-)
--
2.1.4
From: David Ahern <hidden> Date: 2016-06-02 20:16:42
Move the stripping of the ethernet header from is_ip_tx_frame into the
ipv4 and ipv6 outbound functions. If the packet is destined to a local
address the header is retained since the packet is sent back to netif_rx.
Collapse vrf_send_v4_prep into vrf_process_v4_outbound.
Signed-off-by: David Ahern <redacted>
---
drivers/net/vrf.c | 45 ++++++++++++++++++---------------------------
1 file changed, 18 insertions(+), 27 deletions(-)
From: David Ahern <hidden> Date: 2016-06-02 20:16:43
Add support for locally originated traffic to VRF-local addresses. If
destination device for an skb is the loopback or VRF device then set
its dst to a local version of the VRF cached dst_entry and call netif_rx
to insert the packet onto the rx queue - similar to what is done for
loopback. This patch handles IPv4 support; follow on patch handles IPv6.
With this patch, ping, tcp and udp packets to a local IPv4 address are
successfully routed:
$ ip addr show dev eth1
4: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master red state UP group default qlen 1000
link/ether 02:e0:f9:1c:b9:74 brd ff:ff:ff:ff:ff:ff
inet 10.100.1.1/24 brd 10.100.1.255 scope global eth1
valid_lft forever preferred_lft forever
inet6 2100:1::1/120 scope global
valid_lft forever preferred_lft forever
inet6 fe80::e0:f9ff:fe1c:b974/64 scope link
valid_lft forever preferred_lft forever
$ ping -c1 -I red 10.100.1.1
ping: Warning: source address might be selected on device other than red.
PING 10.100.1.1 (10.100.1.1) from 10.100.1.1 red: 56(84) bytes of data.
64 bytes from 10.100.1.1: icmp_seq=1 ttl=64 time=0.057 ms
This patch also enables use of IPv4 loopback address on the VRF device:
$ ip addr add dev red 127.0.0.1/8
$ ping -c1 -I red 127.0.0.1
PING 127.0.0.1 (127.0.0.1) from 127.0.0.1 red: 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.058 ms
Signed-off-by: David Ahern <redacted>
---
drivers/net/vrf.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 98 insertions(+), 2 deletions(-)
@@ -97,6 +109,34 @@ static struct rtnl_link_stats64 *vrf_get_stats64(struct net_device *dev,returnstats;}+/* Local traffic destined to local address. Reinsert the packet to rx+*path,similartoloopbackhandling.+*/+staticintvrf_local_xmit(structsk_buff*skb,structnet_device*dev,+structdst_entry*dst)+{+intlen=skb->len;++skb_orphan(skb);++skb_dst_set(skb,dst);+skb_dst_force(skb);++/* set pkt_type to avoid skb hitting packet taps twice -+*onceonTxandagaininRxprocessing+*/+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);++returnNETDEV_TX_OK;+}+#if IS_ENABLED(CONFIG_IPV6)staticnetdev_tx_tvrf_process_v6_outbound(structsk_buff*skb,structnet_device*dev)
@@ -175,6 +215,34 @@ static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb,}skb_dst_drop(skb);++/* if dst.dev is loopback or the VRF device again this is locally+*originatedtrafficdestinedtoalocaladdress.Shortcircuit+*toRxpathusingourlocaldst+*/+if(rt->dst.dev==net->loopback_dev||rt->dst.dev==vrf_dev){+structnet_vrf*vrf=netdev_priv(vrf_dev);+structrtable*rth_local;+structdst_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))+gotoerr;++returnvrf_local_xmit(skb,vrf_dev,dst);+}+skb_dst_set(skb,&rt->dst);/* strip the ethernet header added for pass through VRF device */
@@ -381,29 +449,48 @@ static int vrf_output(struct net *net, struct sock *sk, struct sk_buff *skb)staticvoidvrf_rtable_release(structnet_vrf*vrf){structrtable*rth=rtnl_dereference(vrf->rth);+structrtable*rth_local=rtnl_dereference(vrf->rth_local);-rcu_assign_pointer(vrf->rth,NULL);+RCU_INIT_POINTER(vrf->rth,NULL);+RCU_INIT_POINTER(vrf->rth_local,NULL);+synchronize_rcu();if(rth)dst_release(&rth->dst);++if(rth_local)+dst_release(&rth_local->dst);}staticintvrf_rtable_create(structnet_device*dev){structnet_vrf*vrf=netdev_priv(dev);-structrtable*rth;+structrtable*rth,*rth_local;if(!fib_new_table(dev_net(dev),vrf->tb_id))return-ENOMEM;+/* create a dst for routing packets out through a VRF device */rth=rt_dst_alloc(dev,0,RTN_UNICAST,1,1,0);if(!rth)return-ENOMEM;+/* create a dst for local ingress routing - packets sent locally+*tolocaladdressviatheVRFdeviceasaloopback+*/+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->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_local,rth_local);return0;}
@@ -658,10 +745,19 @@ static struct sk_buff *vrf_ip_rcv(struct net_device *vrf_dev,skb->dev=vrf_dev;skb->skb_iif=vrf_dev->ifindex;+/* loopback traffic; do not push through packet taps again.+*Resetpkt_typeforupperlayerstoprocessskb+*/+if(skb->pkt_type==PACKET_LOOPBACK){+skb->pkt_type=PACKET_HOST;+gotoout;+}+skb_push(skb,skb->mac_len);dev_queue_xmit_nit(skb,vrf_dev);skb_pull(skb,skb->mac_len);+out:returnskb;}
From: David Ahern <hidden> Date: 2016-06-02 20:16:44
Add support for locally originated traffic to VRF-local IPv6 addresses.
Similar to IPv4 a local dst is set on the skb and the packet is
reinserted with a call to netif_rx. With this patch, ping, tcp and udp
packets to a local IPv6 address are successfully routed:
$ ip addr show dev eth1
4: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master red state UP group default qlen 1000
link/ether 02:e0:f9:1c:b9:74 brd ff:ff:ff:ff:ff:ff
inet 10.100.1.1/24 brd 10.100.1.255 scope global eth1
valid_lft forever preferred_lft forever
inet6 2100:1::1/120 scope global
valid_lft forever preferred_lft forever
inet6 fe80::e0:f9ff:fe1c:b974/64 scope link
valid_lft forever preferred_lft forever
$ ping6 -c1 -I red 2100:1::1
ping6: Warning: source address might be selected on device other than red.
PING 2100:1::1(2100:1::1) from 2100:1::1 red: 56 data bytes
64 bytes from 2100:1::1: icmp_seq=1 ttl=64 time=0.098 ms
ip6_input is exported so the VRF driver can use it for the dst input
function. The dst_alloc function for IPv4 defaults to setting the input and
output functions; IPv6's does not. VRF does not need to duplicate the Rx path
so just export the ipv6 input function.
Signed-off-by: David Ahern <redacted>
---
drivers/net/vrf.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 85 insertions(+), 4 deletions(-)
@@ -163,6 +164,46 @@ static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,gotoerr;skb_dst_drop(skb);++/* if dst.dev is loopback or the VRF device again this is locally+*originatedtrafficdestinedtoalocaladdress.Shortcircuit+*toRxpathusingourlocaldst+*/+if(dst->dev==net->loopback_dev||dst->dev==dev){+structnet_vrf*vrf=netdev_priv(dev);+structrt6_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();+gotoerr;+}++/* Ordering issue: cached local dst is created on newlink+*beforetheIPv6initialization.Usingthelocaldst+*requiresrt6i_idevtobesetsomakesureitis.+*/+if(unlikely(!rt6_local->rt6i_idev)){+rt6_local->rt6i_idev=in6_dev_get(dev);+if(!rt6_local->rt6i_idev){+rcu_read_unlock();+gotoerr;+}+}++dst=&rt6_local->dst;+dst_hold(dst);++rcu_read_unlock();++returnvrf_local_xmit(skb,dev,&rt6_local->dst);+}+skb_dst_set(skb,dst);/* strip the ethernet header added for pass through VRF device */
@@ -342,27 +383,38 @@ static int vrf_output6(struct net *net, struct sock *sk, struct sk_buff *skb)staticvoidvrf_rt6_release(structnet_vrf*vrf){structrt6_info*rt6=rtnl_dereference(vrf->rt6);+structrt6_info*rt6_local=rtnl_dereference(vrf->rt6_local);-rcu_assign_pointer(vrf->rt6,NULL);+RCU_INIT_POINTER(vrf->rt6,NULL);+RCU_INIT_POINTER(vrf->rt6_local,NULL);+synchronize_rcu();if(rt6)dst_release(&rt6->dst);++if(rt6_local){+if(rt6_local->rt6i_idev)+in6_dev_put(rt6_local->rt6i_idev);++dst_release(&rt6_local->dst);+}}staticintvrf_rt6_create(structnet_device*dev){+intflags=DST_HOST|DST_NOPOLICY|DST_NOXFRM|DST_NOCACHE;structnet_vrf*vrf=netdev_priv(dev);structnet*net=dev_net(dev);structfib6_table*rt6i_table;-structrt6_info*rt6;+structrt6_info*rt6,*rt6_local;intrc=-ENOMEM;rt6i_table=fib6_new_table(net,vrf->tb_id);if(!rt6i_table)gotoout;-rt6=ip6_dst_alloc(net,dev,-DST_HOST|DST_NOPOLICY|DST_NOXFRM|DST_NOCACHE);+/* create a dst for routing packets out a VRF device */+rt6=ip6_dst_alloc(net,dev,flags);if(!rt6)gotoout;
@@ -370,7 +422,25 @@ static int vrf_rt6_create(struct net_device *dev)rt6->rt6i_table=rt6i_table;rt6->dst.output=vrf_output6;++/* create a dst for local routing - packets sent locally+*tolocaladdressviatheVRFdeviceasaloopback+*/+rt6_local=ip6_dst_alloc(net,dev,flags);+if(!rt6_local){+dst_release(&rt6->dst);+gotoout;+}++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_local,rt6_local);rc=0;out:
@@ -716,6 +786,16 @@ static bool ipv6_ndisc_frame(const struct sk_buff *skb)staticstructsk_buff*vrf_ip6_rcv(structnet_device*vrf_dev,structsk_buff*skb){+/* loopback traffic; do not push through packet taps again.+*Resetpkt_typeforupperlayerstoprocessskb+*/+if(skb->pkt_type==PACKET_LOOPBACK){+skb->dev=vrf_dev;+skb->skb_iif=vrf_dev->ifindex;+skb->pkt_type=PACKET_HOST;+gotoout;+}+/* if packet is NDISC keep the ingress interface */if(!ipv6_ndisc_frame(skb)){skb->dev=vrf_dev;
From: David Miller <davem@davemloft.net> Date: 2016-06-06 22:12:32
From: David Ahern <redacted>
Date: Thu, 2 Jun 2016 13:15:09 -0700
Add support for locally originated traffic to VRF-local addresses,
be it addresses on enslaved devices or addresses on the VRF device:
...
Series applied, but I've been wondering what happens to hw offloads
when these VRF devices sit in the middle.
Does TSO et al. still occur properly?
From: David Miller <davem@davemloft.net> Date: 2016-06-06 22:56:45
From: David Miller <davem@davemloft.net>
Date: Mon, 06 Jun 2016 15:12:28 -0700 (PDT)
From: David Ahern <redacted>
Date: Thu, 2 Jun 2016 13:15:09 -0700
quoted
Add support for locally originated traffic to VRF-local addresses,
be it addresses on enslaved devices or addresses on the VRF device:
...
Series applied, but I've been wondering what happens to hw offloads
when these VRF devices sit in the middle.
Does TSO et al. still occur properly?
Actually I have to revert this series, ip6_input() is not an exported
module symbol.
If you're only build testing things like this with everything "=y",
please reconsider.
From: David Ahern <hidden> Date: 2016-06-06 23:01:42
On 6/6/16 4:56 PM, David Miller wrote:
From: David Miller <davem@davemloft.net>
Date: Mon, 06 Jun 2016 15:12:28 -0700 (PDT)
quoted
From: David Ahern <redacted>
Date: Thu, 2 Jun 2016 13:15:09 -0700
quoted
Add support for locally originated traffic to VRF-local addresses,
be it addresses on enslaved devices or addresses on the VRF device:
...
Series applied, but I've been wondering what happens to hw offloads
when these VRF devices sit in the middle.
Does TSO et al. still occur properly?
It should, but I will double check and adjust if needed.
Actually I have to revert this series, ip6_input() is not an exported
module symbol.
If you're only build testing things like this with everything "=y",
please reconsider.
As I noted in the commit message "ip6_input is exported so the VRF
driver can use it for the dst input function." It was dropped somewhere
along the way of refactoring for upstream. Will send a v2.