Bug 218508 - Tunneling and aliases using the tun device, reusing a destination address works with IPv4, but not IPv6
Summary: Tunneling and aliases using the tun device, reusing a destination address wor...
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 11.0-RELEASE
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-net (Nobody)
Depends on:
Reported: 2017-04-09 08:29 UTC by Christian Sturm
Modified: 2021-02-25 15:39 UTC (History)
3 users (show)

See Also:


Note You need to log in before you can comment on or make changes to this bug.
Description Christian Sturm 2017-04-09 08:29:27 UTC
I can create a tun device by using:

ifconfig tun0 create
ifconfig tun 
ifconfig tun alias
ifconfig up

This works great and allows me to use the and have it tunneled over the second (aliased) tunnel when I set up the correct route using /sbin/route add -net -iface tun0.

I have this setup, using IPv6 only working as it is supposed to. To explain what I am am actually achieving with this: In the background I am using BGP over a one-to-one VPN software using the tunnel interface.

Doing the same thing on IPv6, however doesn't work when I add an alias, using the same destination address twice:

ifconfig tun0 inet6 fdaa:abc:abc:abc::1 fe80::111:0 prefixlen /128
ifconfig tun0 inet6 alias fe80::111:1 fe80::111:0 prefixlen /128
ifconfig: ioctl (SIOCAIFADDR): File exists

Using another destination address this works however. Since this works on IPv4 I'd expect it to work here as well.
Comment 1 dmilith 2020-07-30 13:40:19 UTC
I have same bug on 12.1… "file exists":

socket(PF_INET,SOCK_DGRAM|SOCK_CLOEXEC,0)        = 3 (0x3)
ioctl(3,SIOCGIFINDEX,0x7fffffff9f20)             = 0 (0x0)
close(3)                                         = 0 (0x0)
__sysctl(0x7fffffff9f40,0x6,0x0,0x7fffffff9f38,0x0,0x0) = 0 (0x0)
__sysctl(0x7fffffff9f40,0x6,0x80161e000,0x7fffffff9f38,0x0,0x0) = 0 (0x0)
socket(PF_INET6,SOCK_DGRAM,0)                    = 3 (0x3)
ioctl(3,SIOCDIFADDR_IN6,0x1054278)               ERR#49 'Can't assign requested address'
ioctl(3,SIOCAIFADDR_IN6,0x1054278)               ERR#17 'File exists'
ifconfig: write(2,"ifconfig: ",10)                       = 10 (0xa)
ioctl (SIOCAIFADDR)write(2,"ioctl (SIOCAIFADDR)",19)             = 19 (0x13)
: write(2,": ",2)                                        = 2 (0x2)
File exists
write(2,"File exists\n",12)                      = 12 (0xc)
process exit, rval = 1
Comment 2 Denton Gentry 2021-02-25 15:39:43 UTC
We've been encountering this in https://github.com/tailscale/tailscale/issues/1307

The problem occurs because rtrequest1_fib returns EEXIST.

root@freebsd12:~ # dtrace -n 'fbt:::return /(int)arg1 == EEXIST / { stack(); }' -c "ifconfig tun0 inet6 fd7a:115c:a1e0:ab12:4843:cd96:625c:1f1b fd7a:115c:a1e0:ab12:4843:cd96:625c:1f1b prefixlen 128"
dtrace: description 'fbt:::return ' matched 29364 probes
ifconfig: ioctl (SIOCAIFADDR): File exists
dtrace: pid 1175 exited with status 1
CPU     ID                    FUNCTION:NAME
  1  52657            rtrequest1_fib:return

That happens because rn_addroute returns NULL:

rn_addroute(void *v_arg, void *n_arg, struct radix_head *head,
    struct radix_node treenodes[2])
         * Deal with duplicated keys: attach node to previous instance
        saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes);
        if (keyduplicated) {
                for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) {
                        /* permit multipath, if enabled for the family */
                        if (tt->rn_mask == netmask)
                                return (0);

There is a bunch of code within the #ifdef RADIX_MPATH block above. Enabling RADIX_MPATH in the kernel config does allow the tun0 address assignment to succeed, though I haven't fully tested if it works as expected.

It looks like this behavior was understood, in a comment in sys/netinet6/in6.c:in6_notify_ifa from 2004:

         * If a new destination address is specified for a point-to-point
         * interface, install a route to the destination as an interface
         * direct route.
         * XXX: the logic below rejects assigning multiple addresses on a p2p.
         * interface that share the same destination.
        plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
        if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 &&
            ia->ia_dstaddr.sin6_family == AF_INET6) {