netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: David Ahern <dsa@cumulusnetworks.com>
To: netdev@vger.kernel.org
Cc: David Ahern <dsa@cumulusnetworks.com>
Subject: [PATCH net-next 08/13] net: vrf: ipv6 support for local traffic to local addresses
Date: Wed,  4 May 2016 20:33:25 -0700	[thread overview]
Message-ID: <1462419210-10463-9-git-send-email-dsa@cumulusnetworks.com> (raw)
In-Reply-To: <1462419210-10463-1-git-send-email-dsa@cumulusnetworks.com>

Add support for locally originated traffic to VRF-local addresses.
This patch handles IPv6 support. With this patch, ping, tcp and udp
packets to a local IPv6 address are successfully routed:

    $ 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. IPv4 defaults to setting the input and output functions; IPv6
does not. VRF does not need to reinvent the Rx path so just export the
function.

Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
---
 drivers/net/vrf.c    | 79 ++++++++++++++++++++++++++++++++++++++++++++--------
 net/ipv6/ip6_input.c |  1 +
 2 files changed, 69 insertions(+), 11 deletions(-)

diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index b6e8b1e9b4fd..7a533607a08c 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -46,6 +46,7 @@ struct net_vrf {
 	struct rtable           *rth;
 	struct rtable           *rth_local;
 	struct rt6_info		*rt6;
+	struct rt6_info		*rt6_local;
 	u32                     tb_id;
 };
 
@@ -148,14 +149,39 @@ static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
 	struct dst_entry *dst;
 	struct dst_entry *dst_null = &net->ipv6.ip6_null_entry->dst;
 
-	/* strip the ethernet header added for pass through VRF device */
-	__skb_pull(skb, skb_network_offset(skb));
-
 	dst = ip6_route_output(net, NULL, &fl6);
 	if (dst == dst_null)
 		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 (dst->dev == net->loopback_dev || dst->dev == dev) {
+		struct net_vrf *vrf = netdev_priv(dev);
+		struct rt6_info *rt6_local = vrf->rt6_local;
+
+		/* release looked up dst and use cached local dst */
+		dst_release(dst);
+
+		/* 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 (!rt6_local->rt6i_idev) {
+			rt6_local->rt6i_idev = in6_dev_get(dev);
+			if (!rt6_local->rt6i_idev)
+				goto err;
+		}
+
+		return vrf_local_xmit(skb, &rt6_local->dst);
+	}
+
+	/* strip the ethernet header added for pass through VRF device */
+	__skb_pull(skb, skb_network_offset(skb));
+
 	skb_dst_set(skb, dst);
 
 	ret = ip6_local_out(net, skb->sk, skb);
@@ -314,30 +340,61 @@ static int vrf_output6(struct net *net, struct sock *sk, struct sk_buff *skb)
 
 static void vrf_rt6_release(struct net_vrf *vrf)
 {
-	dst_release(&vrf->rt6->dst);
+	struct rt6_info *rt6;
+
+	rt6 = vrf->rt6;
+	dst_release(&rt6->dst);
 	vrf->rt6 = NULL;
+
+	rt6 = vrf->rt6_local;
+	if (rt6->rt6i_idev)
+		in6_dev_put(rt6->rt6i_idev);
+
+	dst_release(&rt6->dst);
+	vrf->rt6_local = NULL;
 }
 
 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 *net = dev_net(dev);
+	struct fib6_table *rt6i_table;
 	struct rt6_info *rt6;
 	int rc = -ENOMEM;
 
-	rt6 = ip6_dst_alloc(net, dev,
-			    DST_HOST | DST_NOPOLICY | DST_NOXFRM | DST_NOCACHE);
+	rt6i_table = fib6_new_table(net, vrf->tb_id);
+	if (!rt6i_table)
+		goto out;
+
+	/* create a dst for routing packets out a VRF device */
+	rt6 = ip6_dst_alloc(net, dev, flags);
 	if (!rt6)
 		goto out;
 
 	dst_hold(&rt6->dst);
+	rt6->rt6i_table = rt6i_table;
+	rt6->dst.output = vrf_output6;
+	vrf->rt6 = rt6;
 
-	rt6->rt6i_table = fib6_new_table(net, vrf->tb_id);
-	if (!rt6->rt6i_table)
+	/* create a dst for local routing - packets sent locally
+	 * to local address via the VRF device as a loopback
+	 */
+	rt6 = ip6_dst_alloc(net, dev, flags);
+	if (!rt6) {
+		dst_release(&vrf->rt6->dst);
 		goto out;
+	}
+
+	dst_hold(&rt6->dst);
+
+	rt6->dst.flags |= DST_HOST;
+	rt6->rt6i_idev = in6_dev_get(dev);
+	rt6->rt6i_flags = RTF_UP | RTF_NONEXTHOP | RTF_LOCAL;
+	rt6->rt6i_table = rt6i_table;
+	rt6->dst.input = ip6_input;
+	vrf->rt6_local = rt6;
 
-	rt6->dst.output	= vrf_output6;
-	vrf->rt6 = rt6;
 	rc = 0;
 out:
 	return rc;
@@ -733,7 +790,7 @@ static struct dst_entry *vrf_get_rt6_dst(const struct net_device *dev,
 		dst_hold(&rt->dst);
 	}
 
-	return (struct dst_entry *)rt;
+	return &rt->dst;
 }
 #endif
 
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index f185cbcda114..d896a08be0fc 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -298,6 +298,7 @@ int ip6_input(struct sk_buff *skb)
 		       dev_net(skb->dev), NULL, skb, skb->dev, NULL,
 		       ip6_input_finish);
 }
+EXPORT_SYMBOL_GPL(ip6_input);
 
 int ip6_mc_input(struct sk_buff *skb)
 {
-- 
2.1.4

  parent reply	other threads:[~2016-05-05  3:34 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-05-05  3:33 [PATCH net-next 00/13] net: Various VRF patches David Ahern
2016-05-05  3:33 ` [PATCH net-next 01/13] net: vrf: Create FIB tables on link create David Ahern
2016-05-05  3:33 ` [PATCH net-next 02/13] net: l3mdev: Move get_saddr and rt6_dst David Ahern
2016-05-05  3:33 ` [PATCH net-next 03/13] net: l3mdev: Allow send on enslaved interface David Ahern
2016-05-05  7:40   ` Julian Anastasov
2016-05-05 14:50     ` David Ahern
2016-05-05  3:33 ` [PATCH net-next 04/13] net: ipv6: tcp reset, icmp need to consider L3 domain David Ahern
2016-05-05  3:33 ` [PATCH net-next 05/13] net: l3mdev: Add hook in ip and ipv6 David Ahern
2016-05-05  3:33 ` [PATCH net-next 06/13] net: original ingress device index in PKTINFO David Ahern
2016-05-05  8:41   ` Julian Anastasov
2016-05-05 15:00     ` David Ahern
2016-05-05 20:00       ` Julian Anastasov
2016-05-05  3:33 ` [PATCH net-next 07/13] net: vrf: ipv4 support for local traffic to local addresses David Ahern
2016-05-05  3:33 ` David Ahern [this message]
2016-05-05  3:33 ` [PATCH net-next 09/13] net: l3mdev: Propagate route lookup flags for IPv6 David Ahern
2016-05-05  3:33 ` [PATCH net-next 10/13] net: vrf: Handle ipv6 multicast and link-local addresses David Ahern
2016-05-05  3:33 ` [PATCH net-next 11/13] net: vrf: rcu protect changes to private data David Ahern
2016-05-05  3:33 ` [PATCH net-next 12/13] net: vrf: Implement get_saddr for IPv6 David Ahern
2016-05-05  3:33 ` [PATCH net-next 13/13] net: ipv6: address selection should only consider devices in L3 domain David Ahern
2016-05-05  3:59 ` [PATCH net-next 00/13] net: Various VRF patches David Miller
2016-05-05  4:13   ` David Ahern

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1462419210-10463-9-git-send-email-dsa@cumulusnetworks.com \
    --to=dsa@cumulusnetworks.com \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).