slaacd(8) improve movement between IPv6 & legacy-IP-only networks

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

slaacd(8) improve movement between IPv6 & legacy-IP-only networks

Pamela Mosiejczuk-2
Hi all,

When slaacd(8) detects a link-state change, it sets the preferred
lifetime (pltime) of all configured addresses to zero and tries to
obtain a new router advertisement.

If none is received after some time, slaacd will give up, but existing
configured IPv6 addresses remain. This leads applications to believe
that IPv6 connectivity is available when it is not, leading to
potentially long timeouts. RFC 6059 suggests removing these addresses.

Please test this with IPv6-enabled -> IPv6-enabled transitions (there
should be no regression) and IPv6-enabled -> legacy-only transitions
(things should be improved).

RFC 6059 has additional suggestions about what to do when moving among
various IPv6-enabled networks.

Comments, OKs?



Index: engine.c
===================================================================
RCS file: /cvs/src/sbin/slaacd/engine.c,v
retrieving revision 1.38
diff -u -p -r1.38 engine.c
--- engine.c 26 Aug 2019 18:50:04 -0000 1.38
+++ engine.c 27 Aug 2019 18:20:23 -0000
@@ -91,6 +91,7 @@ enum if_state {
  IF_DELAY,
  IF_PROBE,
  IF_IDLE,
+ IF_DEAD,
 };
 
 const char* if_state_name[] = {
@@ -98,6 +99,7 @@ const char* if_state_name[] = {
  "IF_DELAY",
  "IF_PROBE",
  "IF_IDLE",
+ "IF_DEAD",
 };
 
 enum proposal_state {
@@ -107,6 +109,7 @@ enum proposal_state {
  PROPOSAL_NEARLY_EXPIRED,
  PROPOSAL_WITHDRAWN,
  PROPOSAL_DUPLICATED,
+ PROPOSAL_STALE,
 };
 
 const char* proposal_state_name[] = {
@@ -116,6 +119,7 @@ const char* proposal_state_name[] = {
  "NEARLY_EXPIRED",
  "WITHDRAWN",
  "DUPLICATED",
+ "STALE",
 };
 
 const char* rpref_name[] = {
@@ -245,6 +249,7 @@ void gen_addr(struct slaacd_iface *,
 void gen_address_proposal(struct slaacd_iface *, struct
      radv *, struct radv_prefix *, int);
 void free_address_proposal(struct address_proposal *);
+void withdraw_addr(struct address_proposal *);
 void timeout_from_lifetime(struct address_proposal *);
 void configure_address(struct address_proposal *);
 void in6_prefixlen2mask(struct in6_addr *, int len);
@@ -1996,10 +2001,31 @@ free_address_proposal(struct address_pro
 
  LIST_REMOVE(addr_proposal, entries);
  evtimer_del(&addr_proposal->timer);
+ switch (addr_proposal->state) {
+ case PROPOSAL_STALE:
+ withdraw_addr(addr_proposal);
+ break;
+ default:
+ break;
+ }
  free(addr_proposal);
 }
 
 void
+withdraw_addr(struct address_proposal *addr_proposal)
+{
+ struct imsg_configure_address address;
+
+ log_debug("%s: %d", __func__, addr_proposal->if_index);
+ memset(&address, 0, sizeof(address));
+ address.if_index = addr_proposal->if_index;
+ memcpy(&address.addr, &addr_proposal->addr, sizeof(address.addr));
+
+ engine_imsg_compose_main(IMSG_WITHDRAW_ADDRESS, 0, &address,
+    sizeof(address));
+}
+
+void
 gen_dfr_proposal(struct slaacd_iface *iface, struct radv *ra)
 {
  struct dfr_proposal *dfr_proposal;
@@ -2095,6 +2121,7 @@ free_dfr_proposal(struct dfr_proposal *d
  switch (dfr_proposal->state) {
  case PROPOSAL_CONFIGURED:
  case PROPOSAL_NEARLY_EXPIRED:
+ case PROPOSAL_STALE:
  withdraw_dfr(dfr_proposal);
  break;
  default:
@@ -2235,6 +2262,8 @@ address_proposal_timeout(int fd, short e
  log_debug("%s: address duplicated",
     __func__);
  break;
+ case PROPOSAL_STALE:
+ break;
  default:
  log_debug("%s: unhandled state: %s", __func__,
     proposal_state_name[addr_proposal->state]);
@@ -2327,6 +2356,8 @@ iface_timeout(int fd, short events, void
 {
  struct slaacd_iface *iface = (struct slaacd_iface *)arg;
  struct timeval tv;
+ struct address_proposal *addr_proposal;
+ struct dfr_proposal *dfr_proposal;
 
  log_debug("%s[%d]: %s", __func__, iface->if_index,
     if_state_name[iface->state]);
@@ -2338,12 +2369,26 @@ iface_timeout(int fd, short events, void
  engine_imsg_compose_frontend(
     IMSG_CTL_SEND_SOLICITATION, 0, &iface->if_index,
     sizeof(iface->if_index));
- if (++iface->probes >= MAX_RTR_SOLICITATIONS)
- iface->state = IF_IDLE;
- else {
+ if (++iface->probes >= MAX_RTR_SOLICITATIONS) {
+ iface->state = IF_DEAD;
+ tv.tv_sec = 0;
+ } else
  tv.tv_sec = RTR_SOLICITATION_INTERVAL;
- tv.tv_usec = arc4random_uniform(1000000);
- evtimer_add(&iface->timer, &tv);
+ tv.tv_usec = arc4random_uniform(1000000);
+ evtimer_add(&iface->timer, &tv);
+ break;
+ case IF_DEAD:
+ while(!LIST_EMPTY(&iface->addr_proposals)) {
+ addr_proposal =
+    LIST_FIRST(&iface->addr_proposals);
+ addr_proposal->state = PROPOSAL_STALE;
+ free_address_proposal(addr_proposal);
+ }
+ while(!LIST_EMPTY(&iface->dfr_proposals)) {
+ dfr_proposal =
+    LIST_FIRST(&iface->dfr_proposals);
+ dfr_proposal->state = PROPOSAL_STALE;
+ free_dfr_proposal(dfr_proposal);
  }
  break;
  case IF_DOWN:
Index: slaacd.c
===================================================================
RCS file: /cvs/src/sbin/slaacd/slaacd.c,v
retrieving revision 1.38
diff -u -p -r1.38 slaacd.c
--- slaacd.c 28 Jun 2019 13:32:46 -0000 1.38
+++ slaacd.c 27 Aug 2019 18:20:23 -0000
@@ -65,6 +65,7 @@ void main_dispatch_frontend(int, short,
 void main_dispatch_engine(int, short, void *);
 void handle_proposal(struct imsg_proposal *);
 void configure_interface(struct imsg_configure_address *);
+void delete_address(struct imsg_configure_address *);
 void configure_gateway(struct imsg_configure_dfr *, uint8_t);
 void add_gateway(struct imsg_configure_dfr *);
 void delete_gateway(struct imsg_configure_dfr *);
@@ -519,6 +520,14 @@ main_dispatch_engine(int fd, short event
  memcpy(&address, imsg.data, sizeof(address));
  configure_interface(&address);
  break;
+ case IMSG_WITHDRAW_ADDRESS:
+ if (IMSG_DATA_SIZE(imsg) != sizeof(address))
+ fatalx("%s: IMSG_WITHDRAW_ADDRESS wrong "
+    "length: %lu", __func__,
+    IMSG_DATA_SIZE(imsg));
+ memcpy(&address, imsg.data, sizeof(address));
+ delete_address(&address);
+ break;
  case IMSG_CONFIGURE_DFR:
  if (IMSG_DATA_SIZE(imsg) != sizeof(dfr))
  fatalx("%s: IMSG_CONFIGURE_DFR wrong "
@@ -768,6 +777,32 @@ configure_interface(struct imsg_configur
  if (ioctl(ioctl_sock, SIOCSIFMTU, &ifr) == -1)
     log_warn("failed to set MTU");
  }
+}
+
+void
+delete_address(struct imsg_configure_address *address)
+{
+
+ struct in6_ifreq in6_ridreq;
+ char *if_name;
+
+ memset(&in6_ridreq, 0, sizeof(in6_ridreq));
+
+ if_name = if_indextoname(address->if_index, in6_ridreq.ifr_name);
+ if (if_name == NULL) {
+ log_warnx("%s: cannot find interface %d", __func__,
+    address->if_index);
+ return;
+ }
+
+ memcpy(&in6_ridreq.ifr_ifru, &address->addr,
+    sizeof(in6_ridreq.ifr_ifru));
+
+ log_debug("%s: %s", __func__, if_name);
+
+ if (ioctl(ioctl_sock, SIOCDIFADDR_IN6, &in6_ridreq) == -1)
+ log_warn("%s: cannot remove address", __func__);
+
 }
 
 void
Index: slaacd.h
===================================================================
RCS file: /cvs/src/sbin/slaacd/slaacd.h,v
retrieving revision 1.21
diff -u -p -r1.21 slaacd.h
--- slaacd.h 2 Mar 2019 05:34:59 -0000 1.21
+++ slaacd.h 27 Aug 2019 18:20:23 -0000
@@ -72,6 +72,7 @@ enum imsg_type {
  IMSG_PROPOSAL,
  IMSG_PROPOSAL_ACK,
  IMSG_CONFIGURE_ADDRESS,
+ IMSG_WITHDRAW_ADDRESS,
  IMSG_DEL_ADDRESS,
  IMSG_DEL_ROUTE,
  IMSG_FAKE_ACK,

Reply | Threaded
Open this post in threaded view
|

Re: slaacd(8) improve movement between IPv6 & legacy-IP-only networks

Fernando Gont-2
Hi, Pamela,

On 27/8/19 15:31, Pamela Mosiejczuk wrote:

> Hi all,
>
> When slaacd(8) detects a link-state change, it sets the preferred
> lifetime (pltime) of all configured addresses to zero and tries to
> obtain a new router advertisement.
>
> If none is received after some time, slaacd will give up, but existing
> configured IPv6 addresses remain. This leads applications to believe
> that IPv6 connectivity is available when it is not, leading to
> potentially long timeouts. RFC 6059 suggests removing these addresses.
>
> Please test this with IPv6-enabled -> IPv6-enabled transitions (there
> should be no regression) and IPv6-enabled -> legacy-only transitions
> (things should be improved).
>
> RFC 6059 has additional suggestions about what to do when moving among
> various IPv6-enabled networks.

Just happened to see this (sorry for the bad timing!).

Note: It may be appropriate to remove existing addresses as soon as you
realize you've connected to a different link (e.g., different SSID for
wifi, or if you somehow detect a different net as per RFC6059).

However, a link-state shouldn't, per-se, lead to addresses being
removed. Otherwise, you might break e.g. existing TCP connections upon
transient network problems.

Since we are at it: heads-up:
https://www.ietf.org/internet-drafts/draft-ietf-6man-rfc4941bis-05.txt

Thanks!

Cheers,
--
Fernando Gont
e-mail: [hidden email] || [hidden email]
PGP Fingerprint: 7809 84F5 322E 45C7 F1C9 3945 96EE A9EF D076 FFF1



Reply | Threaded
Open this post in threaded view
|

Re: slaacd(8) improve movement between IPv6 & legacy-IP-only networks

Florian Obser-2
Hi Fernando,

On Thu, Jan 09, 2020 at 08:49:15AM -0300, Fernando Gont wrote:

> Hi, Pamela,
>
> On 27/8/19 15:31, Pamela Mosiejczuk wrote:
> > Hi all,
> >
> > When slaacd(8) detects a link-state change, it sets the preferred
> > lifetime (pltime) of all configured addresses to zero and tries to
> > obtain a new router advertisement.
> >
> > If none is received after some time, slaacd will give up, but existing
> > configured IPv6 addresses remain. This leads applications to believe
> > that IPv6 connectivity is available when it is not, leading to
> > potentially long timeouts. RFC 6059 suggests removing these addresses.
> >
> > Please test this with IPv6-enabled -> IPv6-enabled transitions (there
> > should be no regression) and IPv6-enabled -> legacy-only transitions
> > (things should be improved).
> >
> > RFC 6059 has additional suggestions about what to do when moving among
> > various IPv6-enabled networks.
>
> Just happened to see this (sorry for the bad timing!).
>
> Note: It may be appropriate to remove existing addresses as soon as you
> realize you've connected to a different link (e.g., different SSID for
> wifi, or if you somehow detect a different net as per RFC6059).
>
> However, a link-state shouldn't, per-se, lead to addresses being
> removed. Otherwise, you might break e.g. existing TCP connections upon
> transient network problems.

Pamela is currently busy with other things, so let me jump in here.
I helped testing this and gave a bit of guidance where things are in
slaacd(8) so I know a bit about the history.

This had been considered and was actully my biggest fear so I always
refused to implement something like this. For example what would
happen if you hover right at the edge of wifi reception.

Pamela and others then convinced me to try and see, and operational
experience shows that this is not an issue at all. In fact the diff
has been received overwhelmingly positive. No issues had been reported
at all (and it has been in for a long time).

We don't just nuke addresses on link state change, we go through the
normal procedure of sending 3 router solicitations. Only if we receive
no response do we remove the addreses. This seems to be good enough.

Of course there is still more to implement from RFC 6059 - but the
effects would not be big it seems.

>
> Since we are at it: heads-up:
> https://www.ietf.org/internet-drafts/draft-ietf-6man-rfc4941bis-05.txt
>
> Thanks!
>
> Cheers,
> --
> Fernando Gont
> e-mail: [hidden email] || [hidden email]
> PGP Fingerprint: 7809 84F5 322E 45C7 F1C9 3945 96EE A9EF D076 FFF1
>
>
>

--
I'm not entirely sure you are real.

Reply | Threaded
Open this post in threaded view
|

Re: slaacd(8) improve movement between IPv6 & legacy-IP-only networks

Fernando Gont-2
Hello, Florian,

Apologies for the delay in my response. I was mostly off-line for the
last ten days or so. Inn-line....


On 10/1/20 03:56, Florian Obser wrote:
> Hi Fernando,
>
> On Thu, Jan 09, 2020 at 08:49:15AM -0300, Fernando Gont wrote:
>> Hi, Pamela,
[....]

>>
>> Just happened to see this (sorry for the bad timing!).
>>
>> Note: It may be appropriate to remove existing addresses as soon as you
>> realize you've connected to a different link (e.g., different SSID for
>> wifi, or if you somehow detect a different net as per RFC6059).
>>
>> However, a link-state shouldn't, per-se, lead to addresses being
>> removed. Otherwise, you might break e.g. existing TCP connections upon
>> transient network problems.
>
> Pamela is currently busy with other things, so let me jump in here.
> I helped testing this and gave a bit of guidance where things are in
> slaacd(8) so I know a bit about the history.
>
> This had been considered and was actully my biggest fear so I always
> refused to implement something like this. For example what would
> happen if you hover right at the edge of wifi reception.
>
> Pamela and others then convinced me to try and see, and operational
> experience shows that this is not an issue at all. In fact the diff
> has been received overwhelmingly positive. No issues had been reported
> at all (and it has been in for a long time).
>
> We don't just nuke addresses on link state change, we go through the
> normal procedure of sending 3 router solicitations. Only if we receive
> no response do we remove the addreses. This seems to be good enough.

A couple of things that might be worth considering.

1) If there has been a link sate change, there has been no obvious
indication that the current network attachment point has changed, it may
make sense to keep the addresses. e.g., consider the case where you
experience a link state change, but the AP is the same, or there's no
other advertised prefix, vs. the case where there has been a link state
change event and the AP is a different one and/or a new prefix is
advertised but the previous one isn't.

One might argue that this one is a special case of
https://tools.ietf.org/html/draft-gont-v6ops-slaac-renum-01 , where in
this particular case (the one you've addressed) benefits of link state
signaling, vs. the case we describe in our IETF draft, where you don't
necessarily get link state events. (Proposed protocol updates here:
https://raw.githubusercontent.com/fgont/draft-slaac-renum/master/draft-gont-6man-slaac-renum-02.txt)

P.S.: Bottom-line is that if you cannot positively know you're on a
different net, and you don't hear of a new prefix, you keep the
addresses. And you try to remove them in a timely manner otherwise.

Thanks!

Cheers,
--
Fernando Gont
e-mail: [hidden email] || [hidden email]
PGP Fingerprint: 7809 84F5 322E 45C7 F1C9 3945 96EE A9EF D076 FFF1