Opened 13 years ago

Last modified 4 years ago

#8316 assigned enhancement

Haiku needs IPv6 link scope Auto Configuration

Reported by: kallisti5 Owned by: nobody
Priority: normal Milestone: Unscheduled
Component: Network & Internet/IPv6 Version: R1/Development
Keywords: local scope Cc:
Blocked By: Blocking:
Platform: All

Description (last modified by kallisti5)

Haiku needs to generate a link scope address on all interfaces when the ipv6 module is present.

Here is an example from Linux:

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 14:da:e9:51:54:22 brd ff:ff:ff:ff:ff:ff
    inet 10.10.10.162/24 brd 10.10.10.255 scope global eth0
    inet6 fe80::16da:e9ff:fe51:5422/64 scope link valid_lft forever preferred_lft forever

Attachments (1)

ipv6localLink.diff (10.9 KB ) - added by kallisti5 13 years ago.
v1.0

Download all attachments as: .zip

Change History (21)

comment:1 by kallisti5, 13 years ago

Description: modified (diff)

comment:2 by kallisti5, 13 years ago

ftp://ftp.rfc-editor.org/in-notes/rfc3513.txt

Implementation notes:

IPv6 link scope addresses are based on the MAC address of the card.

Once we have the local link address, we must then perform an ICMPv6 ping to ensure it's available. (Duplicate Address Detection (DAD))

You can find more plain-english descriptions here: http://www.cisco.com/web/about/ac123/ac147/archived_issues/ipj_7-2/ipv6_autoconfig.html

comment:3 by axeld, 13 years ago

Most of this should already be implemented, see http://cgit.haiku-os.org/haiku/tree/src/servers/net/AutoconfigLooper.cpp#n123 and following.

comment:4 by kallisti5, 13 years ago

Wasn't aware that was implemented.. nice job.

All that code depends on INET6 being defined... however grepping through the Haiku tree doesn't result in any spots we define INET6. Is this on purpose?

comment:5 by axeld, 13 years ago

I assume that Atis didn't want to break existing code for his in-progress work on IPv6. Since no one had the time to work on IPv6 in the mean time, no one bothered to remove those defines (I don't think it makes much sense to make that optional; the headers are always there, anyway).

comment:6 by kallisti5, 13 years ago

Ahh..

It's commented out in the net server jam file:

http://cgit.haiku-os.org/haiku/tree/src/servers/net/Jamfile#n13

Also, while the rest of the checks are #ifdef INET6, the following is a plain if...

http://cgit.haiku-os.org/haiku/tree/src/servers/net/NetServer.cpp#n108

comment:7 by kallisti5, 13 years ago

Let me go ahead and remove those #ifdef's as well as the commented out define in the Jamfile.

I'll give it a quick compile and see if we get a stable local ipv6 address... If so committing them out and closing this issue sounds like a resolution to me.

I'll give you an hour before making any changes upstream in case you have other plans. I don't wanna step on your toes.

comment:8 by axeld, 13 years ago

Huh? I have a hard time remembering my last commit ;-) Please just go ahead, if you have the time to test it, my toes certainly don't mind.

comment:9 by kallisti5, 13 years ago

Jeesh.

This change turned from a little fix to a rewrite *real* quick.

Attaching the work I have so far...

This *almost* works, however I am still getting a strange IPv6 address.

I moved the ConfigLinkLocal call to NetServer from the looper... It seemed like a bad place for LinkLocal. (as the looper is only called on autoconfig == true)

always setting up a linklocal address is a good idea because it's not your primary ipv6 address. (ipv6 router advertisement or DHCPv6 would be a good fit for the looper however)

by kallisti5, 13 years ago

Attachment: ipv6localLink.diff added

v1.0

comment:10 by kallisti5, 13 years ago

patch: 01

comment:11 by kallisti5, 13 years ago

committed a much different solution in hrev43721 :)

I think we need to add a few routes as well.. but I have *no* idea what their source + destination should be.

At the moment pinging ::1 doesn't even work though... so testing the actual connectivity is hard.

comment:12 by axeld, 13 years ago

That used to work at some point, though. Dunno what is going wrong now. Does the loopback interface has an IPv6 address?

Version 0, edited 13 years ago by axeld (next)

comment:13 by kallisti5, 13 years ago

Yeah, there is a ::1 address assigned to loopback with a strange prefix length:

inet6 addr: ::1, Prefix Length: 2147512363

there are 0 IPv6 routes though on the system... Maybe digging around would turn up a disabled route setup somewhere?

comment:14 by kallisti5, 13 years ago

My linux machine shows a prefix of 128.

Another question is address scope, it doesn't seem like we have have scope flags for each interface IP. (Scope: link (fe80::), Scope: host(::1), Scope: global(anything else))

The scope is probably the last todo.. we just have to worry about everything breaking when everyone starts using AAAA records.

comment:15 by kallisti5, 13 years ago

bah. that ::1 was a false positive. I was playing with the new network preflet a while back and I added it through that.

current systems don't spin up a loopback for ipv6.

I've dropped code into the network kit to add a loopback ::1, testing now.

comment:16 by luroh, 10 years ago

Milestone: R1Unscheduled

Moving IPv6 related tickets out of R1 milestone.

comment:17 by kallisti5, 8 years ago

patch: 10

comment:18 by axeld, 8 years ago

Owner: changed from axeld to nobody
Status: newassigned

in reply to:  13 comment:19 by jeremyvisser, 4 years ago

Replying to kallisti5:

Yeah, there is a ::1 address assigned to loopback with a strange prefix length:

inet6 addr: ::1, Prefix Length: 2147512363

While I didn't experience this with the loopback address, I did experience this with link local addresses. I had been experimenting locally with hrev45736 reverted to see how the system performed, and I did observe strange prefix lengths on the IPv6 link local addresses.

Though there might be more than one instance of this bug, one bug I found was in net_server's NetServer::_ConfigureIPv6LinkLocal(), where it generates the link local addresses like this:

BNetworkAddress localLinkAddress(addressRaw, 0);
BNetworkAddress localLinkMask("ffff:ffff:ffff:ffff::"); // 64
BNetworkAddress localLinkBroadcast("fe80::ffff:ffff:ffff:ffff");

// ...

BNetworkInterfaceAddress interfaceAddress;
interfaceAddress.SetAddress(localLinkAddress);
interfaceAddress.SetMask(localLinkMask);
interfaceAddress.SetBroadcast(localLinkMask);

interface.AddAddress(interfaceAddress);

I was curious whether this was working as expected, so I dumped the hex contents of the sockaddr of each of the address/mask/broadcast addresses, and I found that they were not working as expected:

  Address (hex):   fe 80 00 00 00 00 00 00 a6 c3 f0 ff fe 67 94 90 
  Mask (hex):      e0 02 73 41 cb 7f 00 00 00 0d 73 41 cb 7f 00 00  <-- random contents each time
  Broadcast (hex): 66 65 64 32 3a 35 35 37 19 00 00 00 00 00 00 00   <-- random contents each time

The random contents suggested uninitialised memory. After further digging I found that BNetworkAddress tries to resolve the string address by calling BNetworkAddressResolver, which was in turn failing (BNetworkAddress::SetTo was returning error, but the constructor ignores the error).

I observed that BNetworkAddressResolver only failed on a fresh boot. After a link local address (with invalid, random mask) was added, subsequent calls to BNetworkAddress localLinkMask("ffff:ffff:ffff:ffff::"); worked as expected.

This suggested the resolver library was failing to resolve IPv6 addresses if no IPv6 addresses are present. Given net_server's job is to add IPv6 addresses in the first place before any exist, this is quite the Catch-22.

I see the following options for solving the problem:

  1. Pass the B_UNCONFIGURED_ADDRESS_FAMILIES flag to the BNetworkAddress in NetServer::_ConfigureIPv6LinkLocal. It appears this tells the resolver to resolve IPv6 addresses regardless of whether it thinks IPv6 is available on the system (which on first boot, it is not yet).
  2. Modify the _ConfigureIPv6LinkLocal function to create the localLinkMask / localLinkBroadcast by passing an in6_addr structure, not a const char *, avoiding the BNetworkAddressResolver altogether. This means no string parsing is needed at all, which is more robust.
  3. Populate the localLinkMask by calling BNetworkAddress::SetToMask(AF_INET6, 64), which is designed for this use case. However this only works for the mask, not broadcast address. That said, I don't know whether the broadcast address is used for anything? (I know it doesn't make sense in IPv6, but does anything in the kernel rely on it? Can it be zeroed out?)
  4. Introduce a mode on the BNetworkAddressResolver or BNetworkAddress which only uses inet_pton() rather than getaddrinfo(). While this is less useful for a generic BNetworkAddress, it is suitable for low-level network config, which net_server does qualify for.
  5. There might be other options I haven't thought of yet.

I'm going to assume Option 1 is preferable (fewest changes required) and prepare a patch for that, but of course there is a lot more work needed to get IPv6 usable so I'd need additional feedback as to whether we think we are ready to uncomment the call to _ConfigureIPv6LinkLocal.

Last edited 4 years ago by jeremyvisser (previous) (diff)

comment:20 by waddlesplash, 4 years ago

I don't know if we are ready to uncomment that call yet, no. I think there are still easily reproducible KDLs in the IPv6 kernel stack (check the relevant components on the bugtracker).

Note: See TracTickets for help on using tickets.