Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Daniel Borkmann and committed by
David S. Miller
f53adae4 9401bb5c

+87 -3
+2
include/net/if_inet6.h
··· 187 187 struct list_head tempaddr_list; 188 188 #endif 189 189 190 + struct in6_addr token; 191 + 190 192 struct neigh_parms *nd_parms; 191 193 struct inet6_dev *next; 192 194 struct ipv6_devconf cnf;
+1
include/uapi/linux/if_link.h
··· 201 201 IFLA_INET6_MCAST, /* MC things. What of them? */ 202 202 IFLA_INET6_CACHEINFO, /* time values and max reasm size */ 203 203 IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */ 204 + IFLA_INET6_TOKEN, /* device token */ 204 205 __IFLA_INET6_MAX 205 206 }; 206 207
+84 -3
net/ipv6/addrconf.c
··· 422 422 ipv6_regen_rndid((unsigned long) ndev); 423 423 } 424 424 #endif 425 + memset(ndev->token.s6_addr, 0, sizeof(ndev->token.s6_addr)); 425 426 426 427 if (netif_running(dev) && addrconf_qdisc_ok(dev)) 427 428 ndev->if_flags |= IF_READY; ··· 2137 2136 2138 2137 if (pinfo->prefix_len == 64) { 2139 2138 memcpy(&addr, &pinfo->prefix, 8); 2140 - if (ipv6_generate_eui64(addr.s6_addr + 8, dev) && 2141 - ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) { 2139 + 2140 + if (!ipv6_addr_any(&in6_dev->token)) { 2141 + read_lock_bh(&in6_dev->lock); 2142 + memcpy(addr.s6_addr + 8, 2143 + in6_dev->token.s6_addr + 8, 8); 2144 + read_unlock_bh(&in6_dev->lock); 2145 + } else if (ipv6_generate_eui64(addr.s6_addr + 8, dev) && 2146 + ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) { 2142 2147 in6_dev_put(in6_dev); 2143 2148 return; 2144 2149 } ··· 4172 4165 + nla_total_size(sizeof(struct ifla_cacheinfo)) 4173 4166 + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ 4174 4167 + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */ 4175 - + nla_total_size(ICMP6_MIB_MAX * 8); /* IFLA_INET6_ICMP6STATS */ 4168 + + nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */ 4169 + + nla_total_size(sizeof(struct in6_addr)); /* IFLA_INET6_TOKEN */ 4176 4170 } 4177 4171 4178 4172 static inline size_t inet6_if_nlmsg_size(void) ··· 4260 4252 goto nla_put_failure; 4261 4253 snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla)); 4262 4254 4255 + nla = nla_reserve(skb, IFLA_INET6_TOKEN, sizeof(struct in6_addr)); 4256 + if (nla == NULL) 4257 + goto nla_put_failure; 4258 + read_lock_bh(&idev->lock); 4259 + memcpy(nla_data(nla), idev->token.s6_addr, nla_len(nla)); 4260 + read_unlock_bh(&idev->lock); 4261 + 4263 4262 return 0; 4264 4263 4265 4264 nla_put_failure: ··· 4292 4277 return -EMSGSIZE; 4293 4278 4294 4279 return 0; 4280 + } 4281 + 4282 + static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token) 4283 + { 4284 + struct in6_addr ll_addr; 4285 + struct inet6_ifaddr *ifp; 4286 + struct net_device *dev = idev->dev; 4287 + 4288 + if (token == NULL) 4289 + return -EINVAL; 4290 + if (ipv6_addr_any(token)) 4291 + return -EINVAL; 4292 + if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) 4293 + return -EINVAL; 4294 + if (idev->dead || !(idev->if_flags & IF_READY)) 4295 + return -EINVAL; 4296 + if (!ipv6_accept_ra(idev)) 4297 + return -EINVAL; 4298 + if (idev->cnf.rtr_solicits <= 0) 4299 + return -EINVAL; 4300 + 4301 + write_lock_bh(&idev->lock); 4302 + 4303 + BUILD_BUG_ON(sizeof(token->s6_addr) != 16); 4304 + memcpy(idev->token.s6_addr + 8, token->s6_addr + 8, 8); 4305 + 4306 + write_unlock_bh(&idev->lock); 4307 + 4308 + ipv6_get_lladdr(dev, &ll_addr, IFA_F_TENTATIVE | IFA_F_OPTIMISTIC); 4309 + ndisc_send_rs(dev, &ll_addr, &in6addr_linklocal_allrouters); 4310 + 4311 + write_lock_bh(&idev->lock); 4312 + idev->if_flags |= IF_RS_SENT; 4313 + 4314 + /* Well, that's kinda nasty ... */ 4315 + list_for_each_entry(ifp, &idev->addr_list, if_list) { 4316 + spin_lock(&ifp->lock); 4317 + if (ipv6_addr_src_scope(&ifp->addr) == 4318 + IPV6_ADDR_SCOPE_GLOBAL) { 4319 + ifp->valid_lft = 0; 4320 + ifp->prefered_lft = 0; 4321 + } 4322 + spin_unlock(&ifp->lock); 4323 + } 4324 + 4325 + write_unlock_bh(&idev->lock); 4326 + return 0; 4327 + } 4328 + 4329 + static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla) 4330 + { 4331 + int err = -EINVAL; 4332 + struct inet6_dev *idev = __in6_dev_get(dev); 4333 + struct nlattr *tb[IFLA_INET6_MAX + 1]; 4334 + 4335 + if (!idev) 4336 + return -EAFNOSUPPORT; 4337 + 4338 + if (nla_parse_nested(tb, IFLA_INET6_MAX, nla, NULL) < 0) 4339 + BUG(); 4340 + 4341 + if (tb[IFLA_INET6_TOKEN]) 4342 + err = inet6_set_iftoken(idev, nla_data(tb[IFLA_INET6_TOKEN])); 4343 + 4344 + return err; 4295 4345 } 4296 4346 4297 4347 static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, ··· 5061 4981 .family = AF_INET6, 5062 4982 .fill_link_af = inet6_fill_link_af, 5063 4983 .get_link_af_size = inet6_get_link_af_size, 4984 + .set_link_af = inet6_set_link_af, 5064 4985 }; 5065 4986 5066 4987 /*