Skip to content

Commit caeaba7

Browse files
NicolasDichteldavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5199dfe commit caeaba7

File tree

2 files changed

+48
-17
lines changed

2 files changed

+48
-17
lines changed

include/net/if_inet6.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ struct inet6_ifaddr {
7474
bool tokenized;
7575

7676
struct rcu_head rcu;
77+
struct in6_addr peer_addr;
7778
};
7879

7980
struct ip6_sf_socklist {

net/ipv6/addrconf.c

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2402,6 +2402,7 @@ int addrconf_set_dstaddr(struct net *net, void __user *arg)
24022402
* Manual configuration of address on an interface
24032403
*/
24042404
static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx,
2405+
const struct in6_addr *peer_pfx,
24052406
unsigned int plen, __u8 ifa_flags, __u32 prefered_lft,
24062407
__u32 valid_lft)
24072408
{
@@ -2457,6 +2458,8 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p
24572458
ifp->valid_lft = valid_lft;
24582459
ifp->prefered_lft = prefered_lft;
24592460
ifp->tstamp = jiffies;
2461+
if (peer_pfx)
2462+
ifp->peer_addr = *peer_pfx;
24602463
spin_unlock_bh(&ifp->lock);
24612464

24622465
addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
@@ -2526,7 +2529,7 @@ int addrconf_add_ifaddr(struct net *net, void __user *arg)
25262529
return -EFAULT;
25272530

25282531
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,
25302533
ireq.ifr6_prefixlen, IFA_F_PERMANENT,
25312534
INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
25322535
rtnl_unlock();
@@ -3610,18 +3613,20 @@ static void addrconf_verify(unsigned long foo)
36103613
rcu_read_unlock_bh();
36113614
}
36123615

3613-
static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local)
3616+
static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local,
3617+
struct in6_addr **peer_pfx)
36143618
{
36153619
struct in6_addr *pfx = NULL;
36163620

3621+
*peer_pfx = NULL;
3622+
36173623
if (addr)
36183624
pfx = nla_data(addr);
36193625

36203626
if (local) {
36213627
if (pfx && nla_memcmp(local, pfx, sizeof(*pfx)))
3622-
pfx = NULL;
3623-
else
3624-
pfx = nla_data(local);
3628+
*peer_pfx = pfx;
3629+
pfx = nla_data(local);
36253630
}
36263631

36273632
return pfx;
@@ -3639,15 +3644,15 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
36393644
struct net *net = sock_net(skb->sk);
36403645
struct ifaddrmsg *ifm;
36413646
struct nlattr *tb[IFA_MAX+1];
3642-
struct in6_addr *pfx;
3647+
struct in6_addr *pfx, *peer_pfx;
36433648
int err;
36443649

36453650
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
36463651
if (err < 0)
36473652
return err;
36483653

36493654
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);
36513656
if (pfx == NULL)
36523657
return -EINVAL;
36533658

@@ -3705,7 +3710,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
37053710
struct net *net = sock_net(skb->sk);
37063711
struct ifaddrmsg *ifm;
37073712
struct nlattr *tb[IFA_MAX+1];
3708-
struct in6_addr *pfx;
3713+
struct in6_addr *pfx, *peer_pfx;
37093714
struct inet6_ifaddr *ifa;
37103715
struct net_device *dev;
37113716
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)
37173722
return err;
37183723

37193724
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);
37213726
if (pfx == NULL)
37223727
return -EINVAL;
37233728

@@ -3745,7 +3750,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
37453750
* It would be best to check for !NLM_F_CREATE here but
37463751
* userspace alreay relies on not having to provide this.
37473752
*/
3748-
return inet6_addr_add(net, ifm->ifa_index, pfx,
3753+
return inet6_addr_add(net, ifm->ifa_index, pfx, peer_pfx,
37493754
ifm->ifa_prefixlen, ifa_flags,
37503755
preferred_lft, valid_lft);
37513756
}
@@ -3802,6 +3807,7 @@ static inline int rt_scope(int ifa_scope)
38023807
static inline int inet6_ifaddr_msgsize(void)
38033808
{
38043809
return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
3810+
+ nla_total_size(16) /* IFA_LOCAL */
38053811
+ nla_total_size(16) /* IFA_ADDRESS */
38063812
+ nla_total_size(sizeof(struct ifa_cacheinfo));
38073813
}
@@ -3840,13 +3846,22 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
38403846
valid = INFINITY_LIFE_TIME;
38413847
}
38423848

3843-
if (nla_put(skb, IFA_ADDRESS, 16, &ifa->addr) < 0 ||
3844-
put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0) {
3845-
nlmsg_cancel(skb, nlh);
3846-
return -EMSGSIZE;
3847-
}
3849+
if (ipv6_addr_type(&ifa->peer_addr) != IPV6_ADDR_ANY) {
3850+
if (nla_put(skb, IFA_LOCAL, 16, &ifa->addr) < 0 ||
3851+
nla_put(skb, IFA_ADDRESS, 16, &ifa->peer_addr) < 0)
3852+
goto error;
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;
38483859

38493860
return nlmsg_end(skb, nlh);
3861+
3862+
error:
3863+
nlmsg_cancel(skb, nlh);
3864+
return -EMSGSIZE;
38503865
}
38513866

38523867
static 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)
40464061
struct net *net = sock_net(in_skb->sk);
40474062
struct ifaddrmsg *ifm;
40484063
struct nlattr *tb[IFA_MAX+1];
4049-
struct in6_addr *addr = NULL;
4064+
struct in6_addr *addr = NULL, *peer;
40504065
struct net_device *dev = NULL;
40514066
struct inet6_ifaddr *ifa;
40524067
struct sk_buff *skb;
@@ -4056,7 +4071,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh)
40564071
if (err < 0)
40574072
goto errout;
40584073

4059-
addr = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]);
4074+
addr = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL], &peer);
40604075
if (addr == NULL) {
40614076
err = -EINVAL;
40624077
goto errout;
@@ -4564,11 +4579,26 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
45644579
ip6_ins_rt(ifp->rt);
45654580
if (ifp->idev->cnf.forwarding)
45664581
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);
45674585
break;
45684586
case RTM_DELADDR:
45694587
if (ifp->idev->cnf.forwarding)
45704588
addrconf_leave_anycast(ifp);
45714589
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+
}
45724602
dst_hold(&ifp->rt->dst);
45734603

45744604
if (ip6_del_rt(ifp->rt))

0 commit comments

Comments
 (0)