All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection
@ 2011-04-14  7:10 Daniel Walter
  2011-04-14 14:01 ` Stephen Clark
  2011-04-15 22:45 ` David Miller
  0 siblings, 2 replies; 12+ messages in thread
From: Daniel Walter @ 2011-04-14  7:10 UTC (permalink / raw)
  To: netdev; +Cc: linux-kernel, davem

[ipv6] Add support for RTA_PREFSRC

This patch allows a user to select the preferred source address
for a specific IPv6-Route. It can be set via a netlink message
setting RTA_PREFSRC to a valid IPv6 address which must be
up on the device the route will be bound to.


Signed-off-by: Daniel Walter <dwalter@barracuda.com>
---
Repost patch, after fixing some warnings pointed out on netdev@
applies clean against current linux-2.6 HEAD

 include/net/ip6_fib.h   |    2 +
 include/net/ip6_route.h |    7 ++++
 net/ipv6/addrconf.c     |    2 +
 net/ipv6/ip6_output.c   |    8 ++--
 net/ipv6/route.c        |   72 +++++++++++++++++++++++++++++++++++++++++++++--
 5 files changed, 84 insertions(+), 7 deletions(-)

---
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index bc3cde0..98348d5 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -42,6 +42,7 @@ struct fib6_config {
 
 	struct in6_addr	fc_dst;
 	struct in6_addr	fc_src;
+	struct in6_addr	fc_prefsrc;
 	struct in6_addr	fc_gateway;
 
 	unsigned long	fc_expires;
@@ -107,6 +108,7 @@ struct rt6_info {
 	struct rt6key			rt6i_dst ____cacheline_aligned_in_smp;
 	u32				rt6i_flags;
 	struct rt6key			rt6i_src;
+	struct rt6key			rt6i_prefsrc;
 	u32				rt6i_metric;
 	u32				rt6i_peer_genid;
 
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index c850e5f..86b1cb4 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -84,6 +84,12 @@ extern int			ip6_route_add(struct fib6_config *cfg);
 extern int			ip6_ins_rt(struct rt6_info *);
 extern int			ip6_del_rt(struct rt6_info *);
 
+extern int			ip6_route_get_saddr(struct net *net,
+						    struct rt6_info *rt,
+						    struct in6_addr *daddr,
+						    unsigned int prefs,
+						    struct in6_addr *saddr);
+
 extern struct rt6_info		*rt6_lookup(struct net *net,
 					    const struct in6_addr *daddr,
 					    const struct in6_addr *saddr,
@@ -141,6 +147,7 @@ struct rt6_rtnl_dump_arg {
 extern int rt6_dump_route(struct rt6_info *rt, void *p_arg);
 extern void rt6_ifdown(struct net *net, struct net_device *dev);
 extern void rt6_mtu_change(struct net_device *dev, unsigned mtu);
+extern void rt6_remove_prefsrc(struct inet6_ifaddr *ifp);
 
 
 /*
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 1493534..129d7e1 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -825,6 +825,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
 		dst_release(&rt->dst);
 	}
 
+	/* clean up prefsrc entries */
+	rt6_remove_prefsrc(ifp);
 out:
 	in6_ifa_put(ifp);
 }
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 46cf7be..1f4c096 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -930,10 +930,10 @@ static int ip6_dst_lookup_tail(struct sock *sk,
 		goto out_err_release;
 
 	if (ipv6_addr_any(&fl6->saddr)) {
-		err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev,
-					 &fl6->daddr,
-					 sk ? inet6_sk(sk)->srcprefs : 0,
-					 &fl6->saddr);
+		struct rt6_info *rt = (struct rt6_info *) *dst;
+		err = ip6_route_get_saddr(net, rt, &fl6->daddr, 
+					  sk ? inet6_sk(sk)->srcprefs : 0,
+					  &fl6->saddr);
 		if (err)
 			goto out_err_release;
 	}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 843406f..af26cc10 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1325,6 +1325,16 @@ int ip6_route_add(struct fib6_config *cfg)
 	if (dev == NULL)
 		goto out;
 
+	if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
+		if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
+			err = -EINVAL;
+			goto out;
+		}
+		ipv6_addr_copy(&rt->rt6i_prefsrc.addr, &cfg->fc_prefsrc);
+		rt->rt6i_prefsrc.plen = 128;
+	} else
+		rt->rt6i_prefsrc.plen = 0;
+
 	if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) {
 		rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev);
 		if (IS_ERR(rt->rt6i_nexthop)) {
@@ -2037,6 +2047,55 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
 	return rt;
 }
 
+int ip6_route_get_saddr(struct net *net,
+			struct rt6_info *rt,
+			struct in6_addr *daddr,
+			unsigned int prefs,
+			struct in6_addr *saddr)
+{
+	struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
+	int err = 0;
+	if (rt->rt6i_prefsrc.plen)
+		ipv6_addr_copy(saddr, &rt->rt6i_prefsrc.addr);
+	else
+		err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
+					 daddr, prefs, saddr);
+	return err;
+}
+
+/* remove deleted ip from prefsrc entries */
+struct arg_dev_net_ip {
+	struct net_device *dev;
+	struct net *net;
+	struct in6_addr *addr;
+};
+
+static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
+{
+	struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
+	struct net *net = ((struct arg_dev_net_ip *)arg)->net;
+	struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
+
+	if (((void *)rt->rt6i_dev == dev || dev == NULL) &&
+	    rt != net->ipv6.ip6_null_entry &&
+	    ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
+		/* remove prefsrc entry */
+		rt->rt6i_prefsrc.plen = 0;
+	}
+	return 0;
+}
+
+void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
+{
+	struct net *net = dev_net(ifp->idev->dev);
+	struct arg_dev_net_ip adni = {
+		.dev = ifp->idev->dev,
+		.net = net,
+		.addr = &ifp->addr,
+	};
+	fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni);
+}
+
 struct arg_dev_net {
 	struct net_device *dev;
 	struct net *net;
@@ -2183,6 +2242,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
 		nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
 	}
 
+	if (tb[RTA_PREFSRC])
+		nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
+
 	if (tb[RTA_OIF])
 		cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
 
@@ -2325,13 +2387,17 @@ static int rt6_fill_node(struct net *net,
 #endif
 			NLA_PUT_U32(skb, RTA_IIF, iif);
 	} else if (dst) {
-		struct inet6_dev *idev = ip6_dst_idev(&rt->dst);
 		struct in6_addr saddr_buf;
-		if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
-				       dst, 0, &saddr_buf) == 0)
+		if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0)
 			NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
 	}
 
+	if (rt->rt6i_prefsrc.plen) {
+		struct in6_addr saddr_buf;
+		ipv6_addr_copy(&saddr_buf, &rt->rt6i_prefsrc.addr);
+		NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
+	}
+
 	if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
 		goto nla_put_failure;
 

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection
  2011-04-14  7:10 [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection Daniel Walter
@ 2011-04-14 14:01 ` Stephen Clark
  2011-04-14 14:24   ` YOSHIFUJI Hideaki
  2011-04-14 14:49   ` Daniel Walter
  2011-04-15 22:45 ` David Miller
  1 sibling, 2 replies; 12+ messages in thread
From: Stephen Clark @ 2011-04-14 14:01 UTC (permalink / raw)
  To: Daniel Walter; +Cc: netdev, linux-kernel, davem

On 04/14/2011 03:10 AM, Daniel Walter wrote:
> [ipv6] Add support for RTA_PREFSRC
>
> This patch allows a user to select the preferred source address
> for a specific IPv6-Route. It can be set via a netlink message
> setting RTA_PREFSRC to a valid IPv6 address which must be
> up on the device the route will be bound to.
>
>
> Signed-off-by: Daniel Walter<dwalter@barracuda.com>
> ---
> Repost patch, after fixing some warnings pointed out on netdev@
> applies clean against current linux-2.6 HEAD
>
>   include/net/ip6_fib.h   |    2 +
>   include/net/ip6_route.h |    7 ++++
>   net/ipv6/addrconf.c     |    2 +
>   net/ipv6/ip6_output.c   |    8 ++--
>   net/ipv6/route.c        |   72 +++++++++++++++++++++++++++++++++++++++++++++--
>   5 files changed, 84 insertions(+), 7 deletions(-)
>
> ---
> diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
> index bc3cde0..98348d5 100644
> --- a/include/net/ip6_fib.h
> +++ b/include/net/ip6_fib.h
> @@ -42,6 +42,7 @@ struct fib6_config {
>
>   	struct in6_addr	fc_dst;
>   	struct in6_addr	fc_src;
> +	struct in6_addr	fc_prefsrc;
>   	struct in6_addr	fc_gateway;
>
>   	unsigned long	fc_expires;
> @@ -107,6 +108,7 @@ struct rt6_info {
>   	struct rt6key			rt6i_dst ____cacheline_aligned_in_smp;
>   	u32				rt6i_flags;
>   	struct rt6key			rt6i_src;
> +	struct rt6key			rt6i_prefsrc;
>   	u32				rt6i_metric;
>   	u32				rt6i_peer_genid;
>
> diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
> index c850e5f..86b1cb4 100644
> --- a/include/net/ip6_route.h
> +++ b/include/net/ip6_route.h
> @@ -84,6 +84,12 @@ extern int			ip6_route_add(struct fib6_config *cfg);
>   extern int			ip6_ins_rt(struct rt6_info *);
>   extern int			ip6_del_rt(struct rt6_info *);
>
> +extern int			ip6_route_get_saddr(struct net *net,
> +						    struct rt6_info *rt,
> +						    struct in6_addr *daddr,
> +						    unsigned int prefs,
> +						    struct in6_addr *saddr);
> +
>   extern struct rt6_info		*rt6_lookup(struct net *net,
>   					    const struct in6_addr *daddr,
>   					    const struct in6_addr *saddr,
> @@ -141,6 +147,7 @@ struct rt6_rtnl_dump_arg {
>   extern int rt6_dump_route(struct rt6_info *rt, void *p_arg);
>   extern void rt6_ifdown(struct net *net, struct net_device *dev);
>   extern void rt6_mtu_change(struct net_device *dev, unsigned mtu);
> +extern void rt6_remove_prefsrc(struct inet6_ifaddr *ifp);
>
>
>   /*
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index 1493534..129d7e1 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -825,6 +825,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
>   		dst_release(&rt->dst);
>   	}
>
> +	/* clean up prefsrc entries */
> +	rt6_remove_prefsrc(ifp);
>   out:
>   	in6_ifa_put(ifp);
>   }
> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
> index 46cf7be..1f4c096 100644
> --- a/net/ipv6/ip6_output.c
> +++ b/net/ipv6/ip6_output.c
> @@ -930,10 +930,10 @@ static int ip6_dst_lookup_tail(struct sock *sk,
>   		goto out_err_release;
>
>   	if (ipv6_addr_any(&fl6->saddr)) {
> -		err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev,
> -					&fl6->daddr,
> -					 sk ? inet6_sk(sk)->srcprefs : 0,
> -					&fl6->saddr);
> +		struct rt6_info *rt = (struct rt6_info *) *dst;
> +		err = ip6_route_get_saddr(net, rt,&fl6->daddr,
> +					  sk ? inet6_sk(sk)->srcprefs : 0,
> +					&fl6->saddr);
>   		if (err)
>   			goto out_err_release;
>   	}
> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> index 843406f..af26cc10 100644
> --- a/net/ipv6/route.c
> +++ b/net/ipv6/route.c
> @@ -1325,6 +1325,16 @@ int ip6_route_add(struct fib6_config *cfg)
>   	if (dev == NULL)
>   		goto out;
>
> +	if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
> +		if (!ipv6_chk_addr(net,&cfg->fc_prefsrc, dev, 0)) {
> +			err = -EINVAL;
> +			goto out;
> +		}
> +		ipv6_addr_copy(&rt->rt6i_prefsrc.addr,&cfg->fc_prefsrc);
> +		rt->rt6i_prefsrc.plen = 128;
> +	} else
> +		rt->rt6i_prefsrc.plen = 0;
> +
>   	if (cfg->fc_flags&  (RTF_GATEWAY | RTF_NONEXTHOP)) {
>   		rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl,&rt->rt6i_gateway, dev);
>   		if (IS_ERR(rt->rt6i_nexthop)) {
> @@ -2037,6 +2047,55 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
>   	return rt;
>   }
>
> +int ip6_route_get_saddr(struct net *net,
> +			struct rt6_info *rt,
> +			struct in6_addr *daddr,
> +			unsigned int prefs,
> +			struct in6_addr *saddr)
> +{
> +	struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
> +	int err = 0;
> +	if (rt->rt6i_prefsrc.plen)
> +		ipv6_addr_copy(saddr,&rt->rt6i_prefsrc.addr);
> +	else
> +		err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
> +					 daddr, prefs, saddr);
> +	return err;
> +}
> +
> +/* remove deleted ip from prefsrc entries */
> +struct arg_dev_net_ip {
> +	struct net_device *dev;
> +	struct net *net;
> +	struct in6_addr *addr;
> +};
> +
> +static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
> +{
> +	struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
> +	struct net *net = ((struct arg_dev_net_ip *)arg)->net;
> +	struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
> +
> +	if (((void *)rt->rt6i_dev == dev || dev == NULL)&&
> +	    rt != net->ipv6.ip6_null_entry&&
> +	    ipv6_addr_equal(addr,&rt->rt6i_prefsrc.addr)) {
> +		/* remove prefsrc entry */
> +		rt->rt6i_prefsrc.plen = 0;
> +	}
> +	return 0;
> +}
> +
> +void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
> +{
> +	struct net *net = dev_net(ifp->idev->dev);
> +	struct arg_dev_net_ip adni = {
> +		.dev = ifp->idev->dev,
> +		.net = net,
> +		.addr =&ifp->addr,
> +	};
> +	fib6_clean_all(net, fib6_remove_prefsrc, 0,&adni);
> +}
> +
>   struct arg_dev_net {
>   	struct net_device *dev;
>   	struct net *net;
> @@ -2183,6 +2242,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
>   		nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
>   	}
>
> +	if (tb[RTA_PREFSRC])
> +		nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
> +
>   	if (tb[RTA_OIF])
>   		cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
>
> @@ -2325,13 +2387,17 @@ static int rt6_fill_node(struct net *net,
>   #endif
>   			NLA_PUT_U32(skb, RTA_IIF, iif);
>   	} else if (dst) {
> -		struct inet6_dev *idev = ip6_dst_idev(&rt->dst);
>   		struct in6_addr saddr_buf;
> -		if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
> -				       dst, 0,&saddr_buf) == 0)
> +		if (ip6_route_get_saddr(net, rt, dst, 0,&saddr_buf) == 0)
>   			NLA_PUT(skb, RTA_PREFSRC, 16,&saddr_buf);
>   	}
>
> +	if (rt->rt6i_prefsrc.plen) {
> +		struct in6_addr saddr_buf;
> +		ipv6_addr_copy(&saddr_buf,&rt->rt6i_prefsrc.addr);
> +		NLA_PUT(skb, RTA_PREFSRC, 16,&saddr_buf);
> +	}
> +
>   	if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst))<  0)
>   		goto nla_put_failure;

What userspace application will be used to set this?

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection
  2011-04-14 14:01 ` Stephen Clark
@ 2011-04-14 14:24   ` YOSHIFUJI Hideaki
  2011-04-14 14:49   ` Daniel Walter
  1 sibling, 0 replies; 12+ messages in thread
From: YOSHIFUJI Hideaki @ 2011-04-14 14:24 UTC (permalink / raw)
  To: sclark46; +Cc: Daniel Walter, netdev, linux-kernel, davem, yoshfuji

Stephen Clark wrote:
> On 04/14/2011 03:10 AM, Daniel Walter wrote:
> > [ipv6] Add support for RTA_PREFSRC
> >
> > This patch allows a user to select the preferred source address
> > for a specific IPv6-Route. It can be set via a netlink message
> > setting RTA_PREFSRC to a valid IPv6 address which must be
> > up on the device the route will be bound to.

> What userspace application will be used to set this?

I do expect Daniel will submit appropriate patch for iproute2 package
shortly :-)

--yoshfuji


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection
  2011-04-14 14:01 ` Stephen Clark
  2011-04-14 14:24   ` YOSHIFUJI Hideaki
@ 2011-04-14 14:49   ` Daniel Walter
  2011-04-14 15:02     ` Stephen Clark
  1 sibling, 1 reply; 12+ messages in thread
From: Daniel Walter @ 2011-04-14 14:49 UTC (permalink / raw)
  To: Stephen Clark; +Cc: netdev, linux-kernel, davem

On Thu, Apr 14, 2011 at 10:01:09AM -0400, Stephen Clark wrote:
> On 04/14/2011 03:10 AM, Daniel Walter wrote:
> > [ipv6] Add support for RTA_PREFSRC
> >
> > This patch allows a user to select the preferred source address
> > for a specific IPv6-Route. It can be set via a netlink message
> > setting RTA_PREFSRC to a valid IPv6 address which must be
> > up on the device the route will be bound to.
> >
> >
> > Signed-off-by: Daniel Walter<dwalter@barracuda.com>
> > ---
> > Repost patch, after fixing some warnings pointed out on netdev@
> > applies clean against current linux-2.6 HEAD
> >
> >   include/net/ip6_fib.h   |    2 +
> >   include/net/ip6_route.h |    7 ++++
> >   net/ipv6/addrconf.c     |    2 +
> >   net/ipv6/ip6_output.c   |    8 ++--
> >   net/ipv6/route.c        |   72 +++++++++++++++++++++++++++++++++++++++++++++--
> >   5 files changed, 84 insertions(+), 7 deletions(-)
> >
> > ---
> > diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
> > index bc3cde0..98348d5 100644
> > --- a/include/net/ip6_fib.h
> > +++ b/include/net/ip6_fib.h
> > @@ -42,6 +42,7 @@ struct fib6_config {
> >
> >   	struct in6_addr	fc_dst;
> >   	struct in6_addr	fc_src;
> > +	struct in6_addr	fc_prefsrc;
> >   	struct in6_addr	fc_gateway;
> >
> >   	unsigned long	fc_expires;
> > @@ -107,6 +108,7 @@ struct rt6_info {
> >   	struct rt6key			rt6i_dst ____cacheline_aligned_in_smp;
> >   	u32				rt6i_flags;
> >   	struct rt6key			rt6i_src;
> > +	struct rt6key			rt6i_prefsrc;
> >   	u32				rt6i_metric;
> >   	u32				rt6i_peer_genid;
> >
> > diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
> > index c850e5f..86b1cb4 100644
> > --- a/include/net/ip6_route.h
> > +++ b/include/net/ip6_route.h
> > @@ -84,6 +84,12 @@ extern int			ip6_route_add(struct fib6_config *cfg);
> >   extern int			ip6_ins_rt(struct rt6_info *);
> >   extern int			ip6_del_rt(struct rt6_info *);
> >
> > +extern int			ip6_route_get_saddr(struct net *net,
> > +						    struct rt6_info *rt,
> > +						    struct in6_addr *daddr,
> > +						    unsigned int prefs,
> > +						    struct in6_addr *saddr);
> > +
> >   extern struct rt6_info		*rt6_lookup(struct net *net,
> >   					    const struct in6_addr *daddr,
> >   					    const struct in6_addr *saddr,
> > @@ -141,6 +147,7 @@ struct rt6_rtnl_dump_arg {
> >   extern int rt6_dump_route(struct rt6_info *rt, void *p_arg);
> >   extern void rt6_ifdown(struct net *net, struct net_device *dev);
> >   extern void rt6_mtu_change(struct net_device *dev, unsigned mtu);
> > +extern void rt6_remove_prefsrc(struct inet6_ifaddr *ifp);
> >
> >
> >   /*
> > diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> > index 1493534..129d7e1 100644
> > --- a/net/ipv6/addrconf.c
> > +++ b/net/ipv6/addrconf.c
> > @@ -825,6 +825,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
> >   		dst_release(&rt->dst);
> >   	}
> >
> > +	/* clean up prefsrc entries */
> > +	rt6_remove_prefsrc(ifp);
> >   out:
> >   	in6_ifa_put(ifp);
> >   }
> > diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
> > index 46cf7be..1f4c096 100644
> > --- a/net/ipv6/ip6_output.c
> > +++ b/net/ipv6/ip6_output.c
> > @@ -930,10 +930,10 @@ static int ip6_dst_lookup_tail(struct sock *sk,
> >   		goto out_err_release;
> >
> >   	if (ipv6_addr_any(&fl6->saddr)) {
> > -		err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev,
> > -					&fl6->daddr,
> > -					 sk ? inet6_sk(sk)->srcprefs : 0,
> > -					&fl6->saddr);
> > +		struct rt6_info *rt = (struct rt6_info *) *dst;
> > +		err = ip6_route_get_saddr(net, rt,&fl6->daddr,
> > +					  sk ? inet6_sk(sk)->srcprefs : 0,
> > +					&fl6->saddr);
> >   		if (err)
> >   			goto out_err_release;
> >   	}
> > diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> > index 843406f..af26cc10 100644
> > --- a/net/ipv6/route.c
> > +++ b/net/ipv6/route.c
> > @@ -1325,6 +1325,16 @@ int ip6_route_add(struct fib6_config *cfg)
> >   	if (dev == NULL)
> >   		goto out;
> >
> > +	if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
> > +		if (!ipv6_chk_addr(net,&cfg->fc_prefsrc, dev, 0)) {
> > +			err = -EINVAL;
> > +			goto out;
> > +		}
> > +		ipv6_addr_copy(&rt->rt6i_prefsrc.addr,&cfg->fc_prefsrc);
> > +		rt->rt6i_prefsrc.plen = 128;
> > +	} else
> > +		rt->rt6i_prefsrc.plen = 0;
> > +
> >   	if (cfg->fc_flags&  (RTF_GATEWAY | RTF_NONEXTHOP)) {
> >   		rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl,&rt->rt6i_gateway, dev);
> >   		if (IS_ERR(rt->rt6i_nexthop)) {
> > @@ -2037,6 +2047,55 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
> >   	return rt;
> >   }
> >
> > +int ip6_route_get_saddr(struct net *net,
> > +			struct rt6_info *rt,
> > +			struct in6_addr *daddr,
> > +			unsigned int prefs,
> > +			struct in6_addr *saddr)
> > +{
> > +	struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
> > +	int err = 0;
> > +	if (rt->rt6i_prefsrc.plen)
> > +		ipv6_addr_copy(saddr,&rt->rt6i_prefsrc.addr);
> > +	else
> > +		err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
> > +					 daddr, prefs, saddr);
> > +	return err;
> > +}
> > +
> > +/* remove deleted ip from prefsrc entries */
> > +struct arg_dev_net_ip {
> > +	struct net_device *dev;
> > +	struct net *net;
> > +	struct in6_addr *addr;
> > +};
> > +
> > +static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
> > +{
> > +	struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
> > +	struct net *net = ((struct arg_dev_net_ip *)arg)->net;
> > +	struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
> > +
> > +	if (((void *)rt->rt6i_dev == dev || dev == NULL)&&
> > +	    rt != net->ipv6.ip6_null_entry&&
> > +	    ipv6_addr_equal(addr,&rt->rt6i_prefsrc.addr)) {
> > +		/* remove prefsrc entry */
> > +		rt->rt6i_prefsrc.plen = 0;
> > +	}
> > +	return 0;
> > +}
> > +
> > +void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
> > +{
> > +	struct net *net = dev_net(ifp->idev->dev);
> > +	struct arg_dev_net_ip adni = {
> > +		.dev = ifp->idev->dev,
> > +		.net = net,
> > +		.addr =&ifp->addr,
> > +	};
> > +	fib6_clean_all(net, fib6_remove_prefsrc, 0,&adni);
> > +}
> > +
> >   struct arg_dev_net {
> >   	struct net_device *dev;
> >   	struct net *net;
> > @@ -2183,6 +2242,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
> >   		nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
> >   	}
> >
> > +	if (tb[RTA_PREFSRC])
> > +		nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
> > +
> >   	if (tb[RTA_OIF])
> >   		cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
> >
> > @@ -2325,13 +2387,17 @@ static int rt6_fill_node(struct net *net,
> >   #endif
> >   			NLA_PUT_U32(skb, RTA_IIF, iif);
> >   	} else if (dst) {
> > -		struct inet6_dev *idev = ip6_dst_idev(&rt->dst);
> >   		struct in6_addr saddr_buf;
> > -		if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
> > -				       dst, 0,&saddr_buf) == 0)
> > +		if (ip6_route_get_saddr(net, rt, dst, 0,&saddr_buf) == 0)
> >   			NLA_PUT(skb, RTA_PREFSRC, 16,&saddr_buf);
> >   	}
> >
> > +	if (rt->rt6i_prefsrc.plen) {
> > +		struct in6_addr saddr_buf;
> > +		ipv6_addr_copy(&saddr_buf,&rt->rt6i_prefsrc.addr);
> > +		NLA_PUT(skb, RTA_PREFSRC, 16,&saddr_buf);
> > +	}
> > +
> >   	if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst))<  0)
> >   		goto nla_put_failure;
> 
> What userspace application will be used to set this?

iproute2 already has support for this, since it is using
RTA_PREFSRC for ipv4. 

ip -6 r a 2001:db8:a::/64 via 2001:db8:b::1 src 2001:db8:b::2


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection
  2011-04-14 14:49   ` Daniel Walter
@ 2011-04-14 15:02     ` Stephen Clark
  0 siblings, 0 replies; 12+ messages in thread
From: Stephen Clark @ 2011-04-14 15:02 UTC (permalink / raw)
  To: Daniel Walter; +Cc: netdev, linux-kernel, davem

On 04/14/2011 10:49 AM, Daniel Walter wrote:
> On Thu, Apr 14, 2011 at 10:01:09AM -0400, Stephen Clark wrote:
>    
>> On 04/14/2011 03:10 AM, Daniel Walter wrote:
>>      
>>> [ipv6] Add support for RTA_PREFSRC
>>>
>>> This patch allows a user to select the preferred source address
>>> for a specific IPv6-Route. It can be set via a netlink message
>>> setting RTA_PREFSRC to a valid IPv6 address which must be
>>> up on the device the route will be bound to.
>>>
>>>
>>> Signed-off-by: Daniel Walter<dwalter@barracuda.com>
>>> ---
>>> Repost patch, after fixing some warnings pointed out on netdev@
>>> applies clean against current linux-2.6 HEAD
>>>
>>>    include/net/ip6_fib.h   |    2 +
>>>    include/net/ip6_route.h |    7 ++++
>>>    net/ipv6/addrconf.c     |    2 +
>>>    net/ipv6/ip6_output.c   |    8 ++--
>>>    net/ipv6/route.c        |   72 +++++++++++++++++++++++++++++++++++++++++++++--
>>>    5 files changed, 84 insertions(+), 7 deletions(-)
>>>
>>> ---
>>> diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
>>> index bc3cde0..98348d5 100644
>>> --- a/include/net/ip6_fib.h
>>> +++ b/include/net/ip6_fib.h
>>> @@ -42,6 +42,7 @@ struct fib6_config {
>>>
>>>    	struct in6_addr	fc_dst;
>>>    	struct in6_addr	fc_src;
>>> +	struct in6_addr	fc_prefsrc;
>>>    	struct in6_addr	fc_gateway;
>>>
>>>    	unsigned long	fc_expires;
>>> @@ -107,6 +108,7 @@ struct rt6_info {
>>>    	struct rt6key			rt6i_dst ____cacheline_aligned_in_smp;
>>>    	u32				rt6i_flags;
>>>    	struct rt6key			rt6i_src;
>>> +	struct rt6key			rt6i_prefsrc;
>>>    	u32				rt6i_metric;
>>>    	u32				rt6i_peer_genid;
>>>
>>> diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
>>> index c850e5f..86b1cb4 100644
>>> --- a/include/net/ip6_route.h
>>> +++ b/include/net/ip6_route.h
>>> @@ -84,6 +84,12 @@ extern int			ip6_route_add(struct fib6_config *cfg);
>>>    extern int			ip6_ins_rt(struct rt6_info *);
>>>    extern int			ip6_del_rt(struct rt6_info *);
>>>
>>> +extern int			ip6_route_get_saddr(struct net *net,
>>> +						    struct rt6_info *rt,
>>> +						    struct in6_addr *daddr,
>>> +						    unsigned int prefs,
>>> +						    struct in6_addr *saddr);
>>> +
>>>    extern struct rt6_info		*rt6_lookup(struct net *net,
>>>    					    const struct in6_addr *daddr,
>>>    					    const struct in6_addr *saddr,
>>> @@ -141,6 +147,7 @@ struct rt6_rtnl_dump_arg {
>>>    extern int rt6_dump_route(struct rt6_info *rt, void *p_arg);
>>>    extern void rt6_ifdown(struct net *net, struct net_device *dev);
>>>    extern void rt6_mtu_change(struct net_device *dev, unsigned mtu);
>>> +extern void rt6_remove_prefsrc(struct inet6_ifaddr *ifp);
>>>
>>>
>>>    /*
>>> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
>>> index 1493534..129d7e1 100644
>>> --- a/net/ipv6/addrconf.c
>>> +++ b/net/ipv6/addrconf.c
>>> @@ -825,6 +825,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
>>>    		dst_release(&rt->dst);
>>>    	}
>>>
>>> +	/* clean up prefsrc entries */
>>> +	rt6_remove_prefsrc(ifp);
>>>    out:
>>>    	in6_ifa_put(ifp);
>>>    }
>>> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
>>> index 46cf7be..1f4c096 100644
>>> --- a/net/ipv6/ip6_output.c
>>> +++ b/net/ipv6/ip6_output.c
>>> @@ -930,10 +930,10 @@ static int ip6_dst_lookup_tail(struct sock *sk,
>>>    		goto out_err_release;
>>>
>>>    	if (ipv6_addr_any(&fl6->saddr)) {
>>> -		err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev,
>>> -					&fl6->daddr,
>>> -					 sk ? inet6_sk(sk)->srcprefs : 0,
>>> -					&fl6->saddr);
>>> +		struct rt6_info *rt = (struct rt6_info *) *dst;
>>> +		err = ip6_route_get_saddr(net, rt,&fl6->daddr,
>>> +					  sk ? inet6_sk(sk)->srcprefs : 0,
>>> +					&fl6->saddr);
>>>    		if (err)
>>>    			goto out_err_release;
>>>    	}
>>> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
>>> index 843406f..af26cc10 100644
>>> --- a/net/ipv6/route.c
>>> +++ b/net/ipv6/route.c
>>> @@ -1325,6 +1325,16 @@ int ip6_route_add(struct fib6_config *cfg)
>>>    	if (dev == NULL)
>>>    		goto out;
>>>
>>> +	if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
>>> +		if (!ipv6_chk_addr(net,&cfg->fc_prefsrc, dev, 0)) {
>>> +			err = -EINVAL;
>>> +			goto out;
>>> +		}
>>> +		ipv6_addr_copy(&rt->rt6i_prefsrc.addr,&cfg->fc_prefsrc);
>>> +		rt->rt6i_prefsrc.plen = 128;
>>> +	} else
>>> +		rt->rt6i_prefsrc.plen = 0;
>>> +
>>>    	if (cfg->fc_flags&   (RTF_GATEWAY | RTF_NONEXTHOP)) {
>>>    		rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl,&rt->rt6i_gateway, dev);
>>>    		if (IS_ERR(rt->rt6i_nexthop)) {
>>> @@ -2037,6 +2047,55 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
>>>    	return rt;
>>>    }
>>>
>>> +int ip6_route_get_saddr(struct net *net,
>>> +			struct rt6_info *rt,
>>> +			struct in6_addr *daddr,
>>> +			unsigned int prefs,
>>> +			struct in6_addr *saddr)
>>> +{
>>> +	struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
>>> +	int err = 0;
>>> +	if (rt->rt6i_prefsrc.plen)
>>> +		ipv6_addr_copy(saddr,&rt->rt6i_prefsrc.addr);
>>> +	else
>>> +		err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
>>> +					 daddr, prefs, saddr);
>>> +	return err;
>>> +}
>>> +
>>> +/* remove deleted ip from prefsrc entries */
>>> +struct arg_dev_net_ip {
>>> +	struct net_device *dev;
>>> +	struct net *net;
>>> +	struct in6_addr *addr;
>>> +};
>>> +
>>> +static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
>>> +{
>>> +	struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
>>> +	struct net *net = ((struct arg_dev_net_ip *)arg)->net;
>>> +	struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
>>> +
>>> +	if (((void *)rt->rt6i_dev == dev || dev == NULL)&&
>>> +	    rt != net->ipv6.ip6_null_entry&&
>>> +	    ipv6_addr_equal(addr,&rt->rt6i_prefsrc.addr)) {
>>> +		/* remove prefsrc entry */
>>> +		rt->rt6i_prefsrc.plen = 0;
>>> +	}
>>> +	return 0;
>>> +}
>>> +
>>> +void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
>>> +{
>>> +	struct net *net = dev_net(ifp->idev->dev);
>>> +	struct arg_dev_net_ip adni = {
>>> +		.dev = ifp->idev->dev,
>>> +		.net = net,
>>> +		.addr =&ifp->addr,
>>> +	};
>>> +	fib6_clean_all(net, fib6_remove_prefsrc, 0,&adni);
>>> +}
>>> +
>>>    struct arg_dev_net {
>>>    	struct net_device *dev;
>>>    	struct net *net;
>>> @@ -2183,6 +2242,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
>>>    		nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
>>>    	}
>>>
>>> +	if (tb[RTA_PREFSRC])
>>> +		nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
>>> +
>>>    	if (tb[RTA_OIF])
>>>    		cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
>>>
>>> @@ -2325,13 +2387,17 @@ static int rt6_fill_node(struct net *net,
>>>    #endif
>>>    			NLA_PUT_U32(skb, RTA_IIF, iif);
>>>    	} else if (dst) {
>>> -		struct inet6_dev *idev = ip6_dst_idev(&rt->dst);
>>>    		struct in6_addr saddr_buf;
>>> -		if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
>>> -				       dst, 0,&saddr_buf) == 0)
>>> +		if (ip6_route_get_saddr(net, rt, dst, 0,&saddr_buf) == 0)
>>>    			NLA_PUT(skb, RTA_PREFSRC, 16,&saddr_buf);
>>>    	}
>>>
>>> +	if (rt->rt6i_prefsrc.plen) {
>>> +		struct in6_addr saddr_buf;
>>> +		ipv6_addr_copy(&saddr_buf,&rt->rt6i_prefsrc.addr);
>>> +		NLA_PUT(skb, RTA_PREFSRC, 16,&saddr_buf);
>>> +	}
>>> +
>>>    	if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst))<   0)
>>>    		goto nla_put_failure;
>>>        
>> What userspace application will be used to set this?
>>      
> iproute2 already has support for this, since it is using
> RTA_PREFSRC for ipv4.
>
> ip -6 r a 2001:db8:a::/64 via 2001:db8:b::1 src 2001:db8:b::2
>
>    
Fantastic!

-- 

"They that give up essential liberty to obtain temporary safety,
deserve neither liberty nor safety."  (Ben Franklin)

"The course of history shows that as a government grows, liberty
decreases."  (Thomas Jefferson)




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection
  2011-04-14  7:10 [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection Daniel Walter
  2011-04-14 14:01 ` Stephen Clark
@ 2011-04-15 22:45 ` David Miller
  1 sibling, 0 replies; 12+ messages in thread
From: David Miller @ 2011-04-15 22:45 UTC (permalink / raw)
  To: sahne; +Cc: netdev, linux-kernel

From: Daniel Walter <sahne@0x90.at>
Date: Thu, 14 Apr 2011 09:10:57 +0200

> [ipv6] Add support for RTA_PREFSRC
> 
> This patch allows a user to select the preferred source address
> for a specific IPv6-Route. It can be set via a netlink message
> setting RTA_PREFSRC to a valid IPv6 address which must be
> up on the device the route will be bound to.
> 
> 
> Signed-off-by: Daniel Walter <dwalter@barracuda.com>

Applied to net-next-2.6

> +		err = ip6_route_get_saddr(net, rt, &fl6->daddr, 
                                                                ^^

This line had trailing whitespace, please avoid this in the future
as GIT complains about it and I have to fix it up by hand.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection
  2011-04-12 22:05   ` David Miller
@ 2011-04-12 22:16     ` David Miller
  -1 siblings, 0 replies; 12+ messages in thread
From: David Miller @ 2011-04-12 22:16 UTC (permalink / raw)
  To: dwalter; +Cc: netdev, linux-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: Text/Plain; charset=utf-8, Size: 1123 bytes --]

From: David Miller <davem@davemloft.net>
Date: Tue, 12 Apr 2011 15:05:11 -0700 (PDT)

> From: Daniel Walter <dwalter@barracuda.com>
> Date: Mon, 11 Apr 2011 09:03:29 +0200
> 
>> [ipv6] Add support for RTA_PREFSRC
>> 
>> This patch allows a user to select the preferred source address
>> for a specific IPv6-Route. It can be set via a netlink message
>> setting RTA_PREFSRC to a valid IPv6 address which must be
>> up on the device the route will be bound to.
>> 
>> 
>> Signed-off-by: Daniel Walter <dwalter@barracuda.com>
> 
> Ok, I can live with this, applied, thanks!

Sorry, I had to revert.

Please fix this warning, test your patch, and resubmit it.

net/ipv6/ip6_output.c: In function ‘ip6_dst_lookup_tail’:
net/ipv6/ip6_output.c:936: warning: passing argument 3 of ‘ip6_route_get_saddr’ from incompatible pointer type
include/net/ip6_route.h:87: note: expected ‘struct in6_addr *’ but argument is of type ‘struct dst_entry **’

Thanks.
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection
@ 2011-04-12 22:16     ` David Miller
  0 siblings, 0 replies; 12+ messages in thread
From: David Miller @ 2011-04-12 22:16 UTC (permalink / raw)
  To: dwalter; +Cc: netdev, linux-kernel

From: David Miller <davem@davemloft.net>
Date: Tue, 12 Apr 2011 15:05:11 -0700 (PDT)

> From: Daniel Walter <dwalter@barracuda.com>
> Date: Mon, 11 Apr 2011 09:03:29 +0200
> 
>> [ipv6] Add support for RTA_PREFSRC
>> 
>> This patch allows a user to select the preferred source address
>> for a specific IPv6-Route. It can be set via a netlink message
>> setting RTA_PREFSRC to a valid IPv6 address which must be
>> up on the device the route will be bound to.
>> 
>> 
>> Signed-off-by: Daniel Walter <dwalter@barracuda.com>
> 
> Ok, I can live with this, applied, thanks!

Sorry, I had to revert.

Please fix this warning, test your patch, and resubmit it.

net/ipv6/ip6_output.c: In function ‘ip6_dst_lookup_tail’:
net/ipv6/ip6_output.c:936: warning: passing argument 3 of ‘ip6_route_get_saddr’ from incompatible pointer type
include/net/ip6_route.h:87: note: expected ‘struct in6_addr *’ but argument is of type ‘struct dst_entry **’

Thanks.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection
  2011-04-11  7:03 ` Daniel Walter
@ 2011-04-12 22:05   ` David Miller
  -1 siblings, 0 replies; 12+ messages in thread
From: David Miller @ 2011-04-12 22:05 UTC (permalink / raw)
  To: dwalter; +Cc: netdev, linux-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: Text/Plain; charset=utf-8, Size: 629 bytes --]

From: Daniel Walter <dwalter@barracuda.com>
Date: Mon, 11 Apr 2011 09:03:29 +0200

> [ipv6] Add support for RTA_PREFSRC
> 
> This patch allows a user to select the preferred source address
> for a specific IPv6-Route. It can be set via a netlink message
> setting RTA_PREFSRC to a valid IPv6 address which must be
> up on the device the route will be bound to.
> 
> 
> Signed-off-by: Daniel Walter <dwalter@barracuda.com>

Ok, I can live with this, applied, thanks!
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection
@ 2011-04-12 22:05   ` David Miller
  0 siblings, 0 replies; 12+ messages in thread
From: David Miller @ 2011-04-12 22:05 UTC (permalink / raw)
  To: dwalter; +Cc: netdev, linux-kernel

From: Daniel Walter <dwalter@barracuda.com>
Date: Mon, 11 Apr 2011 09:03:29 +0200

> [ipv6] Add support for RTA_PREFSRC
> 
> This patch allows a user to select the preferred source address
> for a specific IPv6-Route. It can be set via a netlink message
> setting RTA_PREFSRC to a valid IPv6 address which must be
> up on the device the route will be bound to.
> 
> 
> Signed-off-by: Daniel Walter <dwalter@barracuda.com>

Ok, I can live with this, applied, thanks!

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection
@ 2011-04-11  7:03 ` Daniel Walter
  0 siblings, 0 replies; 12+ messages in thread
From: Daniel Walter @ 2011-04-11  7:03 UTC (permalink / raw)
  To: netdev; +Cc: linux-kernel, David Miller

[ipv6] Add support for RTA_PREFSRC

This patch allows a user to select the preferred source address
for a specific IPv6-Route. It can be set via a netlink message
setting RTA_PREFSRC to a valid IPv6 address which must be
up on the device the route will be bound to.


Signed-off-by: Daniel Walter <dwalter@barracuda.com>
---
Repost patch, after fixing some issues pointed out on netdev@
applies clean against current linux-2.6 HEAD

 include/net/ip6_fib.h   |    2 +
 include/net/ip6_route.h |    7 ++++
 net/ipv6/addrconf.c     |    2 +
 net/ipv6/ip6_output.c   |    8 ++--
 net/ipv6/route.c        |   72 +++++++++++++++++++++++++++++++++++++++++++++--
 5 files changed, 84 insertions(+), 7 deletions(-)

---
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index bc3cde0..98348d5 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -42,6 +42,7 @@ struct fib6_config {
 
 	struct in6_addr	fc_dst;
 	struct in6_addr	fc_src;
+	struct in6_addr	fc_prefsrc;
 	struct in6_addr	fc_gateway;
 
 	unsigned long	fc_expires;
@@ -107,6 +108,7 @@ struct rt6_info {
 	struct rt6key			rt6i_dst ____cacheline_aligned_in_smp;
 	u32				rt6i_flags;
 	struct rt6key			rt6i_src;
+	struct rt6key			rt6i_prefsrc;
 	u32				rt6i_metric;
 	u32				rt6i_peer_genid;
 
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index c850e5f..86b1cb4 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -84,6 +84,12 @@ extern int			ip6_route_add(struct fib6_config *cfg);
 extern int			ip6_ins_rt(struct rt6_info *);
 extern int			ip6_del_rt(struct rt6_info *);
 
+extern int			ip6_route_get_saddr(struct net *net,
+						    struct rt6_info *rt,
+						    struct in6_addr *daddr,
+						    unsigned int prefs,
+						    struct in6_addr *saddr);
+
 extern struct rt6_info		*rt6_lookup(struct net *net,
 					    const struct in6_addr *daddr,
 					    const struct in6_addr *saddr,
@@ -141,6 +147,7 @@ struct rt6_rtnl_dump_arg {
 extern int rt6_dump_route(struct rt6_info *rt, void *p_arg);
 extern void rt6_ifdown(struct net *net, struct net_device *dev);
 extern void rt6_mtu_change(struct net_device *dev, unsigned mtu);
+extern void rt6_remove_prefsrc(struct inet6_ifaddr *ifp);
 
 
 /*
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 3daaf3c..26f9e14 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -825,6 +825,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
 		dst_release(&rt->dst);
 	}
 
+	/* clean up prefsrc entries */
+	rt6_remove_prefsrc(ifp);
 out:
 	in6_ifa_put(ifp);
 }
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 1820887..0ce081b 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -930,10 +930,10 @@ static int ip6_dst_lookup_tail(struct sock *sk,
 		goto out_err_release;
 
 	if (ipv6_addr_any(&fl6->saddr)) {
-		err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev,
-					 &fl6->daddr,
-					 sk ? inet6_sk(sk)->srcprefs : 0,
-					 &fl6->saddr);
+		struct rt6_info *rt = (struct rt6_info *) *dst;
+		err = ip6_route_get_saddr(net, rt, dst,
+					  sk ? inet6_sk(sk)->srcprefs : 0,
+					  &fl6->saddr);
 		if (err)
 			goto out_err_release;
 	}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 843406f..2688b2e 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1325,6 +1325,16 @@ int ip6_route_add(struct fib6_config *cfg)
 	if (dev == NULL)
 		goto out;
 
+	if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
+		if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
+			err = -EINVAL;
+			goto out;
+		}
+		ipv6_addr_copy(&rt->rt6i_prefsrc.addr, &cfg->fc_prefsrc);
+		rt->rt6i_prefsrc.plen = 128;
+	} else
+		rt->rt6i_prefsrc.plen = 0;
+
 	if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) {
 		rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev);
 		if (IS_ERR(rt->rt6i_nexthop)) {
@@ -2037,6 +2047,55 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
 	return rt;
 }
 
+int ip6_route_get_saddr(struct net *net,
+			struct rt6_info *rt,
+			struct in6_addr *daddr,
+			unsigned int prefs,
+			struct in6_addr *saddr)
+{
+	struct inet6_dev *idev = ip6_dst_idev(&rt->dst);
+	int err = 0;
+	if (rt->rt6i_prefsrc.plen)
+		ipv6_addr_copy(saddr, &rt->rt6i_prefsrc.addr);
+	else
+		err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
+					 daddr, prefs, saddr);
+	return err;
+}
+
+/* remove deleted ip from prefsrc entries */
+struct arg_dev_net_ip {
+	struct net_device *dev;
+	struct net *net;
+	struct in6_addr *addr;
+};
+
+static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
+{
+	struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
+	struct net *net = ((struct arg_dev_net_ip *)arg)->net;
+	struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
+
+	if (((void *)rt->rt6i_dev == dev || dev == NULL) &&
+	    rt != net->ipv6.ip6_null_entry &&
+	    ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
+		/* remove prefsrc entry */
+		rt->rt6i_prefsrc.plen = 0;
+	}
+	return 0;
+}
+
+void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
+{
+	struct net *net = dev_net(ifp->idev->dev);
+	struct arg_dev_net_ip adni = {
+		.dev = ifp->idev->dev,
+		.net = net,
+		.addr = &ifp->addr,
+	};
+	fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni);
+}
+
 struct arg_dev_net {
 	struct net_device *dev;
 	struct net *net;
@@ -2183,6 +2242,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
 		nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
 	}
 
+	if (tb[RTA_PREFSRC])
+		nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
+
 	if (tb[RTA_OIF])
 		cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
 
@@ -2325,13 +2387,17 @@ static int rt6_fill_node(struct net *net,
 #endif
 			NLA_PUT_U32(skb, RTA_IIF, iif);
 	} else if (dst) {
-		struct inet6_dev *idev = ip6_dst_idev(&rt->dst);
 		struct in6_addr saddr_buf;
-		if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
-				       dst, 0, &saddr_buf) == 0)
+		if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0)
 			NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
 	}
 
+	if (rt->rt6i_prefsrc.plen) {
+		struct in6_addr saddr_buf;
+		ipv6_addr_copy(&saddr_buf, &rt->rt6i_prefsrc.addr);
+		NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
+	}
+
 	if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
 		goto nla_put_failure;
 




Barracuda Networks AG
Vorsitzender des Aufsichtsrates/ Chairman of the supervisory board: Dean Drako
Vorstand/ Executive Board: Dr. Wieland Alge, Mag. Guenter Klausner
Sitz der Gesellschaft/ Registered office: 6020 Innsbruck, Austria
Handelsgericht Innsbruck Firmenbuch/ Registration Number: 184392s
UID-Nr/ VAT Number: ATU47509003

Diese Nachricht und allfaellige angehaengte Dokumente sind vertraulich und nur fuer den/die Adressaten bestimmt. Sollten Sie nicht der beabsichtigte Adressat sein, ist jede Offenlegung, Weiterleitung oder sonstige Verwendung dieser Information nicht gestattet. In diesem Fall bitten wir, den Absender zu verstaendigen und die Information zu vernichten. Fuer Uebermittlungsfehler oder sonstige Irrtuemer bei Uebermittlung besteht keine Haftung.

This message and any attached files are confidential and intended solely for the addressee(s). Any publication, transmission or other use of the information by a person or entity other than the intended addressee is prohibited. If you receive this in error please contact the sender and delete the material. The sender does not accept liability for any errors or omissions as a result of the transmission.


Barracuda Networks solutions are now available as virtual appliances. 
Visit www.barracudanetworks.com/vx for more information.




^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection
@ 2011-04-11  7:03 ` Daniel Walter
  0 siblings, 0 replies; 12+ messages in thread
From: Daniel Walter @ 2011-04-11  7:03 UTC (permalink / raw)
  To: netdev; +Cc: linux-kernel, David Miller

[ipv6] Add support for RTA_PREFSRC

This patch allows a user to select the preferred source address
for a specific IPv6-Route. It can be set via a netlink message
setting RTA_PREFSRC to a valid IPv6 address which must be
up on the device the route will be bound to.


Signed-off-by: Daniel Walter <dwalter@barracuda.com>
---
Repost patch, after fixing some issues pointed out on netdev@
applies clean against current linux-2.6 HEAD

 include/net/ip6_fib.h   |    2 +
 include/net/ip6_route.h |    7 ++++
 net/ipv6/addrconf.c     |    2 +
 net/ipv6/ip6_output.c   |    8 ++--
 net/ipv6/route.c        |   72 +++++++++++++++++++++++++++++++++++++++++++++--
 5 files changed, 84 insertions(+), 7 deletions(-)

---
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index bc3cde0..98348d5 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -42,6 +42,7 @@ struct fib6_config {
 
 	struct in6_addr	fc_dst;
 	struct in6_addr	fc_src;
+	struct in6_addr	fc_prefsrc;
 	struct in6_addr	fc_gateway;
 
 	unsigned long	fc_expires;
@@ -107,6 +108,7 @@ struct rt6_info {
 	struct rt6key			rt6i_dst ____cacheline_aligned_in_smp;
 	u32				rt6i_flags;
 	struct rt6key			rt6i_src;
+	struct rt6key			rt6i_prefsrc;
 	u32				rt6i_metric;
 	u32				rt6i_peer_genid;
 
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index c850e5f..86b1cb4 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -84,6 +84,12 @@ extern int			ip6_route_add(struct fib6_config *cfg);
 extern int			ip6_ins_rt(struct rt6_info *);
 extern int			ip6_del_rt(struct rt6_info *);
 
+extern int			ip6_route_get_saddr(struct net *net,
+						    struct rt6_info *rt,
+						    struct in6_addr *daddr,
+						    unsigned int prefs,
+						    struct in6_addr *saddr);
+
 extern struct rt6_info		*rt6_lookup(struct net *net,
 					    const struct in6_addr *daddr,
 					    const struct in6_addr *saddr,
@@ -141,6 +147,7 @@ struct rt6_rtnl_dump_arg {
 extern int rt6_dump_route(struct rt6_info *rt, void *p_arg);
 extern void rt6_ifdown(struct net *net, struct net_device *dev);
 extern void rt6_mtu_change(struct net_device *dev, unsigned mtu);
+extern void rt6_remove_prefsrc(struct inet6_ifaddr *ifp);
 
 
 /*
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 3daaf3c..26f9e14 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -825,6 +825,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
 		dst_release(&rt->dst);
 	}
 
+	/* clean up prefsrc entries */
+	rt6_remove_prefsrc(ifp);
 out:
 	in6_ifa_put(ifp);
 }
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 1820887..0ce081b 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -930,10 +930,10 @@ static int ip6_dst_lookup_tail(struct sock *sk,
 		goto out_err_release;
 
 	if (ipv6_addr_any(&fl6->saddr)) {
-		err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev,
-					 &fl6->daddr,
-					 sk ? inet6_sk(sk)->srcprefs : 0,
-					 &fl6->saddr);
+		struct rt6_info *rt = (struct rt6_info *) *dst;
+		err = ip6_route_get_saddr(net, rt, dst,
+					  sk ? inet6_sk(sk)->srcprefs : 0,
+					  &fl6->saddr);
 		if (err)
 			goto out_err_release;
 	}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 843406f..2688b2e 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1325,6 +1325,16 @@ int ip6_route_add(struct fib6_config *cfg)
 	if (dev == NULL)
 		goto out;
 
+	if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
+		if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
+			err = -EINVAL;
+			goto out;
+		}
+		ipv6_addr_copy(&rt->rt6i_prefsrc.addr, &cfg->fc_prefsrc);
+		rt->rt6i_prefsrc.plen = 128;
+	} else
+		rt->rt6i_prefsrc.plen = 0;
+
 	if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) {
 		rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev);
 		if (IS_ERR(rt->rt6i_nexthop)) {
@@ -2037,6 +2047,55 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
 	return rt;
 }
 
+int ip6_route_get_saddr(struct net *net,
+			struct rt6_info *rt,
+			struct in6_addr *daddr,
+			unsigned int prefs,
+			struct in6_addr *saddr)
+{
+	struct inet6_dev *idev = ip6_dst_idev(&rt->dst);
+	int err = 0;
+	if (rt->rt6i_prefsrc.plen)
+		ipv6_addr_copy(saddr, &rt->rt6i_prefsrc.addr);
+	else
+		err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
+					 daddr, prefs, saddr);
+	return err;
+}
+
+/* remove deleted ip from prefsrc entries */
+struct arg_dev_net_ip {
+	struct net_device *dev;
+	struct net *net;
+	struct in6_addr *addr;
+};
+
+static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg)
+{
+	struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev;
+	struct net *net = ((struct arg_dev_net_ip *)arg)->net;
+	struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr;
+
+	if (((void *)rt->rt6i_dev == dev || dev == NULL) &&
+	    rt != net->ipv6.ip6_null_entry &&
+	    ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) {
+		/* remove prefsrc entry */
+		rt->rt6i_prefsrc.plen = 0;
+	}
+	return 0;
+}
+
+void rt6_remove_prefsrc(struct inet6_ifaddr *ifp)
+{
+	struct net *net = dev_net(ifp->idev->dev);
+	struct arg_dev_net_ip adni = {
+		.dev = ifp->idev->dev,
+		.net = net,
+		.addr = &ifp->addr,
+	};
+	fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni);
+}
+
 struct arg_dev_net {
 	struct net_device *dev;
 	struct net *net;
@@ -2183,6 +2242,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
 		nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen);
 	}
 
+	if (tb[RTA_PREFSRC])
+		nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16);
+
 	if (tb[RTA_OIF])
 		cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]);
 
@@ -2325,13 +2387,17 @@ static int rt6_fill_node(struct net *net,
 #endif
 			NLA_PUT_U32(skb, RTA_IIF, iif);
 	} else if (dst) {
-		struct inet6_dev *idev = ip6_dst_idev(&rt->dst);
 		struct in6_addr saddr_buf;
-		if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL,
-				       dst, 0, &saddr_buf) == 0)
+		if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0)
 			NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
 	}
 
+	if (rt->rt6i_prefsrc.plen) {
+		struct in6_addr saddr_buf;
+		ipv6_addr_copy(&saddr_buf, &rt->rt6i_prefsrc.addr);
+		NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
+	}
+
 	if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
 		goto nla_put_failure;
 




Barracuda Networks AG
Vorsitzender des Aufsichtsrates/ Chairman of the supervisory board: Dean Drako
Vorstand/ Executive Board: Dr. Wieland Alge, Mag. Guenter Klausner
Sitz der Gesellschaft/ Registered office: 6020 Innsbruck, Austria
Handelsgericht Innsbruck Firmenbuch/ Registration Number: 184392s
UID-Nr/ VAT Number: ATU47509003

Diese Nachricht und allfaellige angehaengte Dokumente sind vertraulich und nur fuer den/die Adressaten bestimmt. Sollten Sie nicht der beabsichtigte Adressat sein, ist jede Offenlegung, Weiterleitung oder sonstige Verwendung dieser Information nicht gestattet. In diesem Fall bitten wir, den Absender zu verstaendigen und die Information zu vernichten. Fuer Uebermittlungsfehler oder sonstige Irrtuemer bei Uebermittlung besteht keine Haftung.

This message and any attached files are confidential and intended solely for the addressee(s). Any publication, transmission or other use of the information by a person or entity other than the intended addressee is prohibited. If you receive this in error please contact the sender and delete the material. The sender does not accept liability for any errors or omissions as a result of the transmission.


Barracuda Networks solutions are now available as virtual appliances. 
Visit www.barracudanetworks.com/vx for more information.



^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2011-04-15 22:46 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-04-14  7:10 [PATCH 1/1] ipv6: RTA_PREFSRC support for ipv6 route source address selection Daniel Walter
2011-04-14 14:01 ` Stephen Clark
2011-04-14 14:24   ` YOSHIFUJI Hideaki
2011-04-14 14:49   ` Daniel Walter
2011-04-14 15:02     ` Stephen Clark
2011-04-15 22:45 ` David Miller
  -- strict thread matches above, loose matches on Subject: below --
2011-04-11  7:03 Daniel Walter
2011-04-11  7:03 ` Daniel Walter
2011-04-12 22:05 ` David Miller
2011-04-12 22:05   ` David Miller
2011-04-12 22:16   ` David Miller
2011-04-12 22:16     ` David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.