aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2013-05-16 18:32:00 -0400
committerDavid S. Miller <davem@davemloft.net>2013-05-19 18:09:26 -0400
commitcaeaba79009c2ee858c3b2bf8caf922cd719fead (patch)
treeee7e04fe068584f7e88a382c9ba615a71fffcfe9 /net/ipv6/addrconf.c
parent5199dfe531db19f3ac76542753849877e9854441 (diff)
ipv6: add support of peer address
This patch adds the support of peer address for IPv6. For example, it is possible to specify the remote end of a 6inY tunnel. This was already possible in IPv4: ip addr add ip1 peer ip2 dev dev1 The peer address is specified with IFA_ADDRESS and the local address with IFA_LOCAL (like explained in include/uapi/linux/if_addr.h). Note that the API is not changed, because before this patch, it was not possible to specify two different addresses in IFA_LOCAL and IFA_REMOTE. There is a small change for the dump: if the peer is different from ::, IFA_ADDRESS will contain the peer address instead of the local address. Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c64
1 files changed, 47 insertions, 17 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index d1ab6ab29a55..d684d23bc027 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2402,6 +2402,7 @@ err_exit:
2402 * Manual configuration of address on an interface 2402 * Manual configuration of address on an interface
2403 */ 2403 */
2404static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx, 2404static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx,
2405 const struct in6_addr *peer_pfx,
2405 unsigned int plen, __u8 ifa_flags, __u32 prefered_lft, 2406 unsigned int plen, __u8 ifa_flags, __u32 prefered_lft,
2406 __u32 valid_lft) 2407 __u32 valid_lft)
2407{ 2408{
@@ -2457,6 +2458,8 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p
2457 ifp->valid_lft = valid_lft; 2458 ifp->valid_lft = valid_lft;
2458 ifp->prefered_lft = prefered_lft; 2459 ifp->prefered_lft = prefered_lft;
2459 ifp->tstamp = jiffies; 2460 ifp->tstamp = jiffies;
2461 if (peer_pfx)
2462 ifp->peer_addr = *peer_pfx;
2460 spin_unlock_bh(&ifp->lock); 2463 spin_unlock_bh(&ifp->lock);
2461 2464
2462 addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 2465 addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
@@ -2526,7 +2529,7 @@ int addrconf_add_ifaddr(struct net *net, void __user *arg)
2526 return -EFAULT; 2529 return -EFAULT;
2527 2530
2528 rtnl_lock(); 2531 rtnl_lock();
2529 err = inet6_addr_add(net, ireq.ifr6_ifindex, &ireq.ifr6_addr, 2532 err = inet6_addr_add(net, ireq.ifr6_ifindex, &ireq.ifr6_addr, NULL,
2530 ireq.ifr6_prefixlen, IFA_F_PERMANENT, 2533 ireq.ifr6_prefixlen, IFA_F_PERMANENT,
2531 INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); 2534 INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
2532 rtnl_unlock(); 2535 rtnl_unlock();
@@ -3610,18 +3613,20 @@ restart:
3610 rcu_read_unlock_bh(); 3613 rcu_read_unlock_bh();
3611} 3614}
3612 3615
3613static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local) 3616static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local,
3617 struct in6_addr **peer_pfx)
3614{ 3618{
3615 struct in6_addr *pfx = NULL; 3619 struct in6_addr *pfx = NULL;
3616 3620
3621 *peer_pfx = NULL;
3622
3617 if (addr) 3623 if (addr)
3618 pfx = nla_data(addr); 3624 pfx = nla_data(addr);
3619 3625
3620 if (local) { 3626 if (local) {
3621 if (pfx && nla_memcmp(local, pfx, sizeof(*pfx))) 3627 if (pfx && nla_memcmp(local, pfx, sizeof(*pfx)))
3622 pfx = NULL; 3628 *peer_pfx = pfx;
3623 else 3629 pfx = nla_data(local);
3624 pfx = nla_data(local);
3625 } 3630 }
3626 3631
3627 return pfx; 3632 return pfx;
@@ -3639,7 +3644,7 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
3639 struct net *net = sock_net(skb->sk); 3644 struct net *net = sock_net(skb->sk);
3640 struct ifaddrmsg *ifm; 3645 struct ifaddrmsg *ifm;
3641 struct nlattr *tb[IFA_MAX+1]; 3646 struct nlattr *tb[IFA_MAX+1];
3642 struct in6_addr *pfx; 3647 struct in6_addr *pfx, *peer_pfx;
3643 int err; 3648 int err;
3644 3649
3645 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); 3650 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
@@ -3647,7 +3652,7 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
3647 return err; 3652 return err;
3648 3653
3649 ifm = nlmsg_data(nlh); 3654 ifm = nlmsg_data(nlh);
3650 pfx = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]); 3655 pfx = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL], &peer_pfx);
3651 if (pfx == NULL) 3656 if (pfx == NULL)
3652 return -EINVAL; 3657 return -EINVAL;
3653 3658
@@ -3705,7 +3710,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
3705 struct net *net = sock_net(skb->sk); 3710 struct net *net = sock_net(skb->sk);
3706 struct ifaddrmsg *ifm; 3711 struct ifaddrmsg *ifm;
3707 struct nlattr *tb[IFA_MAX+1]; 3712 struct nlattr *tb[IFA_MAX+1];
3708 struct in6_addr *pfx; 3713 struct in6_addr *pfx, *peer_pfx;
3709 struct inet6_ifaddr *ifa; 3714 struct inet6_ifaddr *ifa;
3710 struct net_device *dev; 3715 struct net_device *dev;
3711 u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME; 3716 u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME;
@@ -3717,7 +3722,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
3717 return err; 3722 return err;
3718 3723
3719 ifm = nlmsg_data(nlh); 3724 ifm = nlmsg_data(nlh);
3720 pfx = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]); 3725 pfx = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL], &peer_pfx);
3721 if (pfx == NULL) 3726 if (pfx == NULL)
3722 return -EINVAL; 3727 return -EINVAL;
3723 3728
@@ -3745,7 +3750,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
3745 * It would be best to check for !NLM_F_CREATE here but 3750 * It would be best to check for !NLM_F_CREATE here but
3746 * userspace alreay relies on not having to provide this. 3751 * userspace alreay relies on not having to provide this.
3747 */ 3752 */
3748 return inet6_addr_add(net, ifm->ifa_index, pfx, 3753 return inet6_addr_add(net, ifm->ifa_index, pfx, peer_pfx,
3749 ifm->ifa_prefixlen, ifa_flags, 3754 ifm->ifa_prefixlen, ifa_flags,
3750 preferred_lft, valid_lft); 3755 preferred_lft, valid_lft);
3751 } 3756 }
@@ -3802,6 +3807,7 @@ static inline int rt_scope(int ifa_scope)
3802static inline int inet6_ifaddr_msgsize(void) 3807static inline int inet6_ifaddr_msgsize(void)
3803{ 3808{
3804 return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) 3809 return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
3810 + nla_total_size(16) /* IFA_LOCAL */
3805 + nla_total_size(16) /* IFA_ADDRESS */ 3811 + nla_total_size(16) /* IFA_ADDRESS */
3806 + nla_total_size(sizeof(struct ifa_cacheinfo)); 3812 + nla_total_size(sizeof(struct ifa_cacheinfo));
3807} 3813}
@@ -3840,13 +3846,22 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
3840 valid = INFINITY_LIFE_TIME; 3846 valid = INFINITY_LIFE_TIME;
3841 } 3847 }
3842 3848
3843 if (nla_put(skb, IFA_ADDRESS, 16, &ifa->addr) < 0 || 3849 if (ipv6_addr_type(&ifa->peer_addr) != IPV6_ADDR_ANY) {
3844 put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0) { 3850 if (nla_put(skb, IFA_LOCAL, 16, &ifa->addr) < 0 ||
3845 nlmsg_cancel(skb, nlh); 3851 nla_put(skb, IFA_ADDRESS, 16, &ifa->peer_addr) < 0)
3846 return -EMSGSIZE; 3852 goto error;
3847 } 3853 } else
3854 if (nla_put(skb, IFA_ADDRESS, 16, &ifa->addr) < 0)
3855 goto error;
3856
3857 if (put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0)
3858 goto error;
3848 3859
3849 return nlmsg_end(skb, nlh); 3860 return nlmsg_end(skb, nlh);
3861
3862error:
3863 nlmsg_cancel(skb, nlh);
3864 return -EMSGSIZE;
3850} 3865}
3851 3866
3852static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, 3867static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca,
@@ -4046,7 +4061,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh)
4046 struct net *net = sock_net(in_skb->sk); 4061 struct net *net = sock_net(in_skb->sk);
4047 struct ifaddrmsg *ifm; 4062 struct ifaddrmsg *ifm;
4048 struct nlattr *tb[IFA_MAX+1]; 4063 struct nlattr *tb[IFA_MAX+1];
4049 struct in6_addr *addr = NULL; 4064 struct in6_addr *addr = NULL, *peer;
4050 struct net_device *dev = NULL; 4065 struct net_device *dev = NULL;
4051 struct inet6_ifaddr *ifa; 4066 struct inet6_ifaddr *ifa;
4052 struct sk_buff *skb; 4067 struct sk_buff *skb;
@@ -4056,7 +4071,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh)
4056 if (err < 0) 4071 if (err < 0)
4057 goto errout; 4072 goto errout;
4058 4073
4059 addr = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]); 4074 addr = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL], &peer);
4060 if (addr == NULL) { 4075 if (addr == NULL) {
4061 err = -EINVAL; 4076 err = -EINVAL;
4062 goto errout; 4077 goto errout;
@@ -4564,11 +4579,26 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
4564 ip6_ins_rt(ifp->rt); 4579 ip6_ins_rt(ifp->rt);
4565 if (ifp->idev->cnf.forwarding) 4580 if (ifp->idev->cnf.forwarding)
4566 addrconf_join_anycast(ifp); 4581 addrconf_join_anycast(ifp);
4582 if (ipv6_addr_type(&ifp->peer_addr) != IPV6_ADDR_ANY)
4583 addrconf_prefix_route(&ifp->peer_addr, 128,
4584 ifp->idev->dev, 0, 0);
4567 break; 4585 break;
4568 case RTM_DELADDR: 4586 case RTM_DELADDR:
4569 if (ifp->idev->cnf.forwarding) 4587 if (ifp->idev->cnf.forwarding)
4570 addrconf_leave_anycast(ifp); 4588 addrconf_leave_anycast(ifp);
4571 addrconf_leave_solict(ifp->idev, &ifp->addr); 4589 addrconf_leave_solict(ifp->idev, &ifp->addr);
4590 if (ipv6_addr_type(&ifp->peer_addr) != IPV6_ADDR_ANY) {
4591 struct rt6_info *rt;
4592 struct net_device *dev = ifp->idev->dev;
4593
4594 rt = rt6_lookup(dev_net(dev), &ifp->peer_addr, NULL,
4595 dev->ifindex, 1);
4596 if (rt) {
4597 dst_hold(&rt->dst);
4598 if (ip6_del_rt(rt))
4599 dst_free(&rt->dst);
4600 }
4601 }
4572 dst_hold(&ifp->rt->dst); 4602 dst_hold(&ifp->rt->dst);
4573 4603
4574 if (ip6_del_rt(ifp->rt)) 4604 if (ip6_del_rt(ifp->rt))