aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Borkmann <dborkman@redhat.com>2013-04-08 00:01:30 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-08 16:55:28 -0400
commitf53adae4eae5ad9f7343ff4a0fc68b468c981138 (patch)
tree86ae2a2fcd5e7c1e8db14479d217df079cc995fb
parent9401bb5c339d2f9529b2f859638440ce92227c83 (diff)
net: ipv6: add tokenized interface identifier support
This patch adds support for IPv6 tokenized IIDs, that allow for administrators to assign well-known host-part addresses to nodes whilst still obtaining global network prefix from Router Advertisements. It is currently in draft status. The primary target for such support is server platforms where addresses are usually manually configured, rather than using DHCPv6 or SLAAC. By using tokenised identifiers, hosts can still determine their network prefix by use of SLAAC, but more readily be automatically renumbered should their network prefix change. [...] The disadvantage with static addresses is that they are likely to require manual editing should the network prefix in use change. If instead there were a method to only manually configure the static identifier part of the IPv6 address, then the address could be automatically updated when a new prefix was introduced, as described in [RFC4192] for example. In such cases a DNS server might be configured with such a tokenised interface identifier of ::53, and SLAAC would use the token in constructing the interface address, using the advertised prefix. [...] http://tools.ietf.org/html/draft-chown-6man-tokenised-ipv6-identifiers-02 The implementation is partially based on top of Mark K. Thompson's proof of concept. However, it uses the Netlink interface for configuration resp. data retrival, so that it can be easily extended in future. Successfully tested by myself. Cc: Hannes Frederic Sowa <hannes@stressinduktion.org> Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Cc: Thomas Graf <tgraf@suug.ch> Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/if_inet6.h2
-rw-r--r--include/uapi/linux/if_link.h1
-rw-r--r--net/ipv6/addrconf.c87
3 files changed, 87 insertions, 3 deletions
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
index 93563221d29a..f1063d62cd13 100644
--- a/include/net/if_inet6.h
+++ b/include/net/if_inet6.h
@@ -187,6 +187,8 @@ struct inet6_dev {
187 struct list_head tempaddr_list; 187 struct list_head tempaddr_list;
188#endif 188#endif
189 189
190 struct in6_addr token;
191
190 struct neigh_parms *nd_parms; 192 struct neigh_parms *nd_parms;
191 struct inet6_dev *next; 193 struct inet6_dev *next;
192 struct ipv6_devconf cnf; 194 struct ipv6_devconf cnf;
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index c4edfe11f1f7..6b35c4211f65 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -201,6 +201,7 @@ enum {
201 IFLA_INET6_MCAST, /* MC things. What of them? */ 201 IFLA_INET6_MCAST, /* MC things. What of them? */
202 IFLA_INET6_CACHEINFO, /* time values and max reasm size */ 202 IFLA_INET6_CACHEINFO, /* time values and max reasm size */
203 IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */ 203 IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */
204 IFLA_INET6_TOKEN, /* device token */
204 __IFLA_INET6_MAX 205 __IFLA_INET6_MAX
205}; 206};
206 207
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index a33b157d9ccf..65d8139d60c5 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -422,6 +422,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
422 ipv6_regen_rndid((unsigned long) ndev); 422 ipv6_regen_rndid((unsigned long) ndev);
423 } 423 }
424#endif 424#endif
425 memset(ndev->token.s6_addr, 0, sizeof(ndev->token.s6_addr));
425 426
426 if (netif_running(dev) && addrconf_qdisc_ok(dev)) 427 if (netif_running(dev) && addrconf_qdisc_ok(dev))
427 ndev->if_flags |= IF_READY; 428 ndev->if_flags |= IF_READY;
@@ -2136,8 +2137,14 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
2136 2137
2137 if (pinfo->prefix_len == 64) { 2138 if (pinfo->prefix_len == 64) {
2138 memcpy(&addr, &pinfo->prefix, 8); 2139 memcpy(&addr, &pinfo->prefix, 8);
2139 if (ipv6_generate_eui64(addr.s6_addr + 8, dev) && 2140
2140 ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) { 2141 if (!ipv6_addr_any(&in6_dev->token)) {
2142 read_lock_bh(&in6_dev->lock);
2143 memcpy(addr.s6_addr + 8,
2144 in6_dev->token.s6_addr + 8, 8);
2145 read_unlock_bh(&in6_dev->lock);
2146 } else if (ipv6_generate_eui64(addr.s6_addr + 8, dev) &&
2147 ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) {
2141 in6_dev_put(in6_dev); 2148 in6_dev_put(in6_dev);
2142 return; 2149 return;
2143 } 2150 }
@@ -4165,7 +4172,8 @@ static inline size_t inet6_ifla6_size(void)
4165 + nla_total_size(sizeof(struct ifla_cacheinfo)) 4172 + nla_total_size(sizeof(struct ifla_cacheinfo))
4166 + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ 4173 + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */
4167 + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */ 4174 + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */
4168 + nla_total_size(ICMP6_MIB_MAX * 8); /* IFLA_INET6_ICMP6STATS */ 4175 + nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */
4176 + nla_total_size(sizeof(struct in6_addr)); /* IFLA_INET6_TOKEN */
4169} 4177}
4170 4178
4171static inline size_t inet6_if_nlmsg_size(void) 4179static inline size_t inet6_if_nlmsg_size(void)
@@ -4252,6 +4260,13 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev)
4252 goto nla_put_failure; 4260 goto nla_put_failure;
4253 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla)); 4261 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla));
4254 4262
4263 nla = nla_reserve(skb, IFLA_INET6_TOKEN, sizeof(struct in6_addr));
4264 if (nla == NULL)
4265 goto nla_put_failure;
4266 read_lock_bh(&idev->lock);
4267 memcpy(nla_data(nla), idev->token.s6_addr, nla_len(nla));
4268 read_unlock_bh(&idev->lock);
4269
4255 return 0; 4270 return 0;
4256 4271
4257nla_put_failure: 4272nla_put_failure:
@@ -4279,6 +4294,71 @@ static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
4279 return 0; 4294 return 0;
4280} 4295}
4281 4296
4297static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
4298{
4299 struct in6_addr ll_addr;
4300 struct inet6_ifaddr *ifp;
4301 struct net_device *dev = idev->dev;
4302
4303 if (token == NULL)
4304 return -EINVAL;
4305 if (ipv6_addr_any(token))
4306 return -EINVAL;
4307 if (dev->flags & (IFF_LOOPBACK | IFF_NOARP))
4308 return -EINVAL;
4309 if (idev->dead || !(idev->if_flags & IF_READY))
4310 return -EINVAL;
4311 if (!ipv6_accept_ra(idev))
4312 return -EINVAL;
4313 if (idev->cnf.rtr_solicits <= 0)
4314 return -EINVAL;
4315
4316 write_lock_bh(&idev->lock);
4317
4318 BUILD_BUG_ON(sizeof(token->s6_addr) != 16);
4319 memcpy(idev->token.s6_addr + 8, token->s6_addr + 8, 8);
4320
4321 write_unlock_bh(&idev->lock);
4322
4323 ipv6_get_lladdr(dev, &ll_addr, IFA_F_TENTATIVE | IFA_F_OPTIMISTIC);
4324 ndisc_send_rs(dev, &ll_addr, &in6addr_linklocal_allrouters);
4325
4326 write_lock_bh(&idev->lock);
4327 idev->if_flags |= IF_RS_SENT;
4328
4329 /* Well, that's kinda nasty ... */
4330 list_for_each_entry(ifp, &idev->addr_list, if_list) {
4331 spin_lock(&ifp->lock);
4332 if (ipv6_addr_src_scope(&ifp->addr) ==
4333 IPV6_ADDR_SCOPE_GLOBAL) {
4334 ifp->valid_lft = 0;
4335 ifp->prefered_lft = 0;
4336 }
4337 spin_unlock(&ifp->lock);
4338 }
4339
4340 write_unlock_bh(&idev->lock);
4341 return 0;
4342}
4343
4344static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla)
4345{
4346 int err = -EINVAL;
4347 struct inet6_dev *idev = __in6_dev_get(dev);
4348 struct nlattr *tb[IFLA_INET6_MAX + 1];
4349
4350 if (!idev)
4351 return -EAFNOSUPPORT;
4352
4353 if (nla_parse_nested(tb, IFLA_INET6_MAX, nla, NULL) < 0)
4354 BUG();
4355
4356 if (tb[IFLA_INET6_TOKEN])
4357 err = inet6_set_iftoken(idev, nla_data(tb[IFLA_INET6_TOKEN]));
4358
4359 return err;
4360}
4361
4282static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, 4362static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
4283 u32 portid, u32 seq, int event, unsigned int flags) 4363 u32 portid, u32 seq, int event, unsigned int flags)
4284{ 4364{
@@ -4981,6 +5061,7 @@ static struct rtnl_af_ops inet6_ops = {
4981 .family = AF_INET6, 5061 .family = AF_INET6,
4982 .fill_link_af = inet6_fill_link_af, 5062 .fill_link_af = inet6_fill_link_af,
4983 .get_link_af_size = inet6_get_link_af_size, 5063 .get_link_af_size = inet6_get_link_af_size,
5064 .set_link_af = inet6_set_link_af,
4984}; 5065};
4985 5066
4986/* 5067/*