Subject: Re: comments about draft-chakrabarti-ipv6-addrselect-api-03

From: Erik Nordmark <[email-masked]>
Date: Mon, 31 Oct 2005 10:27:09 -0800

JINMEI Tatuya / 神明達哉 wrote:

> After thinking about it again, I now tend to feel AI_PREFERENCE does
> not sound so ad-hoc.  Sine getaddrinfo() is typically expected to
> return multiple addresses (of multiple families), ordering among them
> is its inherent concern.  So, I think I can live with AI_PREFERENCE
> (and the corresponding additional field(s) of addrinfo{}).

ok

> I'm not really sure what "to only define a single AI flag", but yes,
> I'm still concerned about having separate flags for both PUBLIC and
> TMP (and so on).

FWIW I don't understand the first part of that sentence. Missing "means"
before the comma? Or something else?

> I've been thinking over it again, and I guess the main concerns are as
> follows:
> 
> 1. having separate flags cause invalid cases and make sanity checks in
>    implementations more complex (as I mentioned in the comment
>    message).

But for getaddrinfo I think is an inherent issue. For instance, I don't
see how your proposed list of preferences below (in ai_selections) makes
it any easier to detect conflicts; it might actually make it harder for
all I can tell.

> 2. rephrasing this point differently, these are actually not "flags",
>    but multi(more than 2)-value options.  For example, what we are
>    going to define with IPV6_PREFER_SRC_HOME and IPV6_PREFER_SRC_COA
>    is the source address selection policy from
>      - prefer home address
>      - prefer care-of-address
>      - (perhaps implicitly) use system (or administrator's) default

The 3rd is actually the semantics of "leave unchanged". In the case of
getaddrinfo this would always mean the system default. But in the case
of setsockopt, it would mean to not change the current setting for that
preference on the socket.

>    (I admit this might sound just a "philosophical" argument.)
> 
> As far as I know, in the traditional API design we have been using a
> separate socket option type for each optional notion (in this case the
> address selection policy).  Examples include the IPV6_MULTICAST_LOOP
> option (while it does not have a specific "use default" value) and the
> IPV6_{UNICAST,MULTICAST}_HOPS options (while these have more than two
> possible values).

Yes, one can produce a functional setsockopt setting of preferences by
using a separate socket option for each preference.
Thus
	int on = 1;

	setsockopt(s, IPPROTO_IPV6, IPV6_PREFER_COA, &on, sizeof(on));
to prefer CoA over HOA and
	int off = 0;

	setsockopt(s, IPPROTO_IPV6, IPV6_PREFER_COA, &off, sizeof(off));
to turn it off, and likewise for the separate socket options for
IPV6_PREFER_TMP, IPV6_PREFER_CGA, etc.

That would imply a large number of separate socket options.

But the important thing is that such a change could have no impact on
how we specify getaddrinfo(), since there we have to be able to specify
everything in a single call.

> I speculate one of the reasons why we've been adhering to the use of
> "flags" is because we need to do the similar thing for getaddrinfo()
> and the only available field to pass this information was a "flag"
> field at that time.  If my understanding is correct, and if we agree
> on some (more flexible) extensions to the addrinfo structure, we may
> be able to take a different approach.

> For example, we'd be able to specify each policy as an integer
> encoding a type-value pair, and specify the set of policies as an
> array of the pairs.  The following describes one possible
> implementation of this idea.
> 
> typedef struct {
> 	u_int32_t policyname : 30;
> 	u_int32_t policyvalue : 2;
> } ai_selection_t;
> 
> struct addrinfo {
>   int     ai_flags;     /* AI_PASSIVE, AI_CANONNAME,
>                            AI_NUMERICHOST, .. */
>   (snip)
>   ai_selection_t *ai_selection; /* examined only when AI_PREFERENCE is
>                                    set and ai_selection is non NULL */
> };
> 
> An application that prefers care-of-address over home-address would
> do:
> 
> 	struct addrinfo hints;
> 	ai_selection_t ai_selections[2];
> 
> 	ai_selections[0].policyname = AI_SELECTION_MIP;
> 	ai_selections[0].policyvalue = AI_SELECTION_PREFER_COA;
> 
> 	/* AI_SELECTION_NULL is a terminating marker */
> 	ai_selections[1].policyname = AI_SELECTION_NULL;
> 	ai_selections[1].policyvalue = 0;
> 
> 	hints.ai_flags |= AI_PREFERENCE;
> 	hints.ai_selection = ai_selections;
> 
> How about something like this?  One may regard this as an
> overly-generalized solution, but I believe this solves all technical
> concerns pointed out so far.

I don't see how this is any simpler. The implementation becomes more
complex because it needs to handle an array of preferences instead of a
single value. And the implementation still need to have checks against
specifying different values for the same preference, doesn't it?
For example, if the application does
	ai_selections[0].policyname = AI_SELECTION_MIP;
	ai_selections[0].policyvalue = AI_SELECTION_PREFER_COA;
	ai_selections[1].policyname = AI_SELECTION_MIP;
	ai_selections[1].policyvalue = AI_SELECTION_PREFER_HOME;
	/* AI_SELECTION_NULL is a terminating marker */
	ai_selections[2].policyname = AI_SELECTION_NULL;
	ai_selections[2].policyvalue = 0;

So I don't see the gain in such added generality over a single
ai_preference field.

And I see a disadvantage in having getaddrinfo preferences and
setsockopt preferences working in a different way, since it is the
application programmer that needs to deal with that.

The simplest approach for the application programmer would be to define
a single name space for IPV6_ADDR_PREFER_*, and use that both in
ai_preferences and with setsockopt. In such a case the application code
would be along the lines of
	int preferences = IPV6_PREFER_COA | IPV6_PREFER_TMP;

	hints.ai_flags |= AI_PREFERENCE;
	hints.ai_preferences = preferences;
	getaddrinfo(...);
	/* Loop over all returned addresses */
	while (ai != NULL) {
		s = socket(ai->ai_family, ...);
		setsockopt(s, IPV^_PREFERENCES, &preferences,
		    sizeof (preferences));
		if (connect(s, ai->ai_addr, ai->ai_addrlen) == -1)
			continue;
		break;
	}

Such code would be more complex for all the other approaches we've
discussed. And the single preference name space would make it easier to
provide a
	int connect_by_name(char *hostname, int port, int preferences);
library function (which would help move the complexity of trying
multiple addresses out of the applications).

    Erik

--------------------------------------------------------------------
IETF IPv6 working group mailing list
[email-masked]
Administrative Requests: https://www1.ietf.org/mailman/listinfo/ipv6
--------------------------------------------------------------------

---

From: Erik Nordmark <[email-masked]>
Date: Mon, 31 Oct 2005 10:29:04 -0800

I have list of intended edits based on the bulk of your comments. Here
are some comments on the non-trivial parts.

JINMEI Tatuya / 神明達哉 wrote:

> I'm afraid you misunderstood my point.  (Perhaps the additional
> question obscured the main point...)  My main question is:
> 
>   In my understanding, if either of the flags of a particular rule is
>   off, it means the system default should be used for that rule.  For
>   example, if 'flags = IPV6_PREFER_SRC_TMP', then the system default
>   will apply for HOME vs COA, CGA vs NONCGA, etc.  Is that correct?
>   If so, when an application wants to make the rules revert to system
>   default, it should be able to call setsockopt without setting any
>   flag, shouldn't it?  Or in other wise, it does not have to remember
>   the old rule values by calling getsockopt beforehand for this
>   purpose.

No, it isn't "apply system default", it is "leave unchanged".

Given that a socket starts with the system default, then subsequent
setsockopts of IPV6_PREFERENCES can be used to tweak different
preferences; one setsockopt can specify public vs. tmp preferences, and
a different setsockopt can specify home vs. coa.

> Maybe we can simply say the sending host cannot *always* detect
> whether the destination is reached via tunnel.  Additional explanation
> you mentioned above may also help, but I don't have a particular
> opinion on how much of the details we should provide here.

ok

> Yes, and this leads me to think we should rather define other variants
> of IN6_IS_ADDR_xxx().  That is,
> 
> 	in6_is_addr_home()
> 	in6_is_addr_careof()
> 	in6_is_addr_temporary()
> 	in6_is_addr_cga()

You mean that each of those would just take an struct sockaddr * as an
argument?
And return true/false?

What if the address in question isn't even assigned to the host i.e. the
host can't determine whether it is of a particular category?

> etc.  Or, it's probably better not to adhere to recycling the
> IPV6_PREFER_xxx "flags" for multiple purposes, and consider something
> like this:
> 
> 	int in6_getaddrattr(struct sockaddr_in6 *addr, uint32_t *attrp);
> 
> On success, this function returns 0 and sets the "attributes" of the
> address as bit-wise flags in '*attrp'.  The flags are, for example,
> 
> 	IN6_ADDRATTR_HOME
> 	IN6_ADDRATTR_COA (not sure if we need this in addition to HOME
> 	                  though)
> 	IN6_ADDRATTR_TMP
> 	IN6_ADDRATTR_CGA

This seems like more work than definining a handful of specific
in6_is_addr_*() functions.

I'm not sure this generality is worth-while.

    Erik

---

From: Erik Nordmark <[email-masked]>
Date: Mon, 31 Oct 2005 10:29:22 -0800

INMEI Tatuya / 神明達哉 wrote:

> As for the relevance to the addrselct API, I was confused about one
> point.  New applications that support this API would probably test the
> availability of the flag first like this:
> 
> 	hints.ai_flags = 0;
> #ifdef AI_NEWFLAG
> 	hints.ai_flags |= AI_NEWFLAG;
> #endif
> 	getaddrinfo(..., &hints, ..);
> 
> Thus, the problem occurs only when the flag definition and the
> getaddrinfo() implementation are inconsistent (as Mark pointed out).
> It would be fair to say such inconsistency is a bug and ignore such a
> case.
> 
> I think it's still helpful if the addrselect document assumes the
> consistency between the supported flag definitions and the
> getaddrinfo() implementation.

We can add this to the document.

    Erik