Subject: [rrg] ILNP: stack behavior to work with IPv6 apps?

From: Robin Whittle <[email-masked]>
Date: Tue, 13 Jul 2010 01:51:21 +1000

Hi Ran, Tony and Steve,

One of the key features claimed for ILNP is that it can work properly
with unmodified IPv6 applications.  By this I mean that it can
provide host-multihoming, site-multihoming and mobility, between two
hosts with ILNP-equipped stacks, between all applications.

This has already been stated:

   RRG Report Summary:

      ILNP can be implemented such that existing applications (e.g.
      applications using the BSD Sockets API) do NOT need any changes
      or modifications to use ILNP.

   draft-rja-ilnp-intro-05:

      9.1 BSD Sockets APIs

      The existing BSD Sockets API can continue to be used with
      ILNP underneath the API.  That API can be implemented in a
      manner that hides the underlying protocol changes from the
      applications.

I am trying to understand how the stack would achieve this.  Here is
my attempt to figure it out, with various questions I hope you can
answer.

To simplify the discussion, I assume:

   ILNPv6 only.

   BSD sockets interface only with the application using stream
   and datagram calls (TCP and 2-way UDP) and performing all DNS
   queries via getaddrinfo().  (There would be quite a few apps which
   use raw sockets, do their own DNS lookups etc.  I doubt these
   could work with ILNP.)

   The application starts with FQDNs as the mechanism to specify the
   one or more hosts it will communicate with.  (I think quite a
   few applications have other mechanisms for determining the IP
   addresses of hosts they communicate with.  As far as I know,
   these won't work with ILNP - these involve IP-address
   "referrals".)

   All Identifiers are globally unique.

   I assume a single Identifier is returned from the lookup of the
   FQDNs.  (ILNP can implement the equivalent of round-robin DNS
   by having the DNS return multiple Identifiers, but they must
   all share the same Locators - that is, these hosts must all have
   the same sets of ISPs, so they are accessible via the same set of
   /64 prefixes.)

   I am not trying to check the system for robustness against attacks
   - just trying to imagine how it would work in the simplest
   realistic case I can imagine.

The example (to be continued in later messages) concerns 3 ILNP hosts
A, B and C and a fourth, ordinary, IPv6 host D, whose IP address I
will depict as "KKKK-LLLL".

I am using four characters to represent 64 bits, so "PPPP-QQQQ" means
the upper 64 bits (Locator) are symbolized by "PPPP" and the lower 64
bits (Identifier) by "QQQQ".  "0000-QQQQ" denotes the upper 64 bits
being zero.

  Host            A            B            C            D

  FQDN for        A.FOO.NET    B.BAR.NET    C.BAZ.NET    D.ZOT.NET
  this host

  IP address
  from the point
  of view of
  ordinary IPv6
  applications    EEEE-AAAA    GGGG-BBBB    IIII-CCCC    KKKK-LLLL

  Identifier      AAAA         BBBB         CCCC

  Locators        EEEE         GGGG         IIII
                  FFFF         HHHH         JJJJ

A, B and C are multihomed via two ISPs each.  From the point of view
of the routing system (globally, and down to their local network
level) each of A, B and C has two IP addresses.  For instance, A has
both:

  EEEE-AAAA  and  FFFF-AAAA

I assume that the ILNP-modified stack either presents to the IPv6
apps in A the impression that A has both addresses, or only makes one
available.  (How this would be chosen, and how it would work, I have
not tried to figure out.)  I will assume each ILNP stack only
presents the first of its host's two IP addresses to ordinary IPv6
applications as the host's address.

If D initiates a session with any of the applications in A, B or C -
perhaps via the one IP addresses which the ILNP stack supports for
ordinary IPv6 communications - the ILNP stack in A, B or C needs to
behave exactly like an ordinary IPv6 stack, so the applications at
each host can communicate as usual.

In principle this can be decided by the stack seeing the initial
packet from D arrive without an extension header with an ILNP nonce.

     (BTW, an ILNP host only sends a nonce on the "Initial" packet.
      This is easy to figure out with a TCP session, but what about
      an application on A which starts sending UDP packets to a novel
      destination host, say host C?   The ILNP stack in A might have
      some algorithm to decide that the first outgoing UDP packet to
      C is "initial" - and so would add the nonce.  I foresee
      problems with Path MTU Discovery - how could it do this and
      somehow tell the application a realistic maximum size for the
      UDP payload, when the first packet has this extra nonce
      header?

      But let's say that first packet is lost.  The application
      retries - and the ILNP stack in A has no reason to consider
      this second packet to C as being "initial" - so it doesn't add
      a nonce.

      The first packet to arrive at C is the second packet - without
      a nonce.  So the ILNP stack in C will decide that A is not an
      ILNP equipped host, and will treat the packet exactly like an
      ordinary IPv6 stack.  There will be no way after that for C to
      discover that A was really an ILNP host.

      It seems this reliance on sending a nonce only on the "initial"
      packet is rather fragile.)

Now I will try to imagine how B runs a server on TCP port 80 and A
has a web client on TCP 2000, which sends an initial packet (TCP SYN)
to B's port 80.

The web client application in A initiates this session by starting
with "B.BAR.NET".  It uses getaddrinfo() to do a DNS lookup of this
FQDN and the ILNP-stack processes this and sends a request packet to
the DNS.  The reply arrives at A's ILNP-equipped stack.  (I will
assume the query requested all records and that there is no LP
record, so the full results come back in the reply.)  The reply includes:

   ID:     BBBB   Preference 1

   L64:    GGGG   Preference 1
   L64:    HHHH   Preference 2

The ILNP stack keeps note of these items.  I won't try to imagine the
exact details, though the I-Ds give details of the state the stack
keeps for each session.

What IP address does the ILNP-stack return to the web client
application?

    GGGG-BBBB
 or 0000-BBBB?

There will be other things in the returned structure addrinfo, but
the only one which matters to us now is the binary address contained
in the sockaddr structure within addrinfo.  I assume that only one
addrinfo will be returned, and not two, such as with GGGG-BBBB and
HHHH-BBBB.

The ILNP I-Ds do not seem to specify how the stack returns the
results of DNS queries to applications.  The three items which seem
most relevant are:

  draft-rja-ilnp-icmp-02

      5. Backwards Compatibility

          For all sessions operating in Identifier/Locator Split
          mode, inside each node the high-order 64-bits ("Locator")
          are always set to zero before the packet is sent upwards to
          the transport protocol.

  draft-rja-ilnp-intro-05

      3. TRANSPORT PROTOCOLS

          With this proposal, transport protocols include only the
          Identifier in their pseudo-header calculations, but do not
          include the Locator in their pseudo-header calculations.

          To minimise the changes required within transport protocol
          implementations, when this proposal is in use for a
          communications session, the Locator fields are zeroed for
          the purpose of transport-layer pseudo-header calculations.

      9.1 BSD Sockets APIs

          The existing BSD Sockets API can continue to be used with
          ILNP underneath the API.  That API can be implemented in a
          manner that hides the underlying protocol changes from the
          applications.  For example, the combination of a Locator
          and an Identifier can be used with the API in the place
          of an IPv6 address.

The first and second items above imply that the application would be
given 0000-BBBB.  The third implies that it would be given GGGG-BBBB.

How would the ILNP stack behave?

I will continue on the assumption that the ILNP stack gives the
application 0000-BBBB - because this makes more sense to me than
giving it GGGG-BBBB and then letting it open a socket to GGGG-BBBB,
when the upper bits are to be zeroed, for the purpose of
pseudo-header calculations, and then replaced (when constructing the
destination address) with the ILNP stack's choice of GGGG or HHHH.

So the web client application gets the IP address 0000-BBBB and opens
a socket with this address to be the destination address of the
resulting TCP packets.  It then calls connect() and the ILNP stack
sends a TCP SYN packet to, I assume GGGG-BBBB.  The ILNP stack in A
determines this is an "initial packet" and so adds a destination
option with a unique ILNP nonce.  I assume that the source address of
the packet leaving A is EEEE-AAAA, but it just as easily could be
FFFF-AAAA.  I will assume it is sent from TCP port 3333.

Before this, what must have happened in host B for the web server
application to have opened what it thinks is a socket on its own IP
address?  I assume the ILNP stack has told the application the host's
IP address is GGGG-BBBB.

The server application on B must have (in order for the ILNP stack to
retain backwards compatibility with IPv6) opened what for all intents
and purposes is an ordinary TCP Listen socket on its IP address
GGGG-BBBB, port 80.

If a web client in D sends an ordinary IPv6 packet to TCP port 80 at
B's IP address HHHH.BBBB, then I assume the ILNP stack will ignore
it, because the server application hasn't opened a socket on this
address.  If the web client on D sends such a packet to GGGG.BBBB,
then the ILNP stack in B must present the packet as usual:  from
KKKK-LLLL, and whatever port number there - so the server application
can respond normally.

For ILNP to work, the ILNP stack in B must be ready to accept packets
with an ILNP nonce, addressed to TCP port 80 on either of its
addresses GGGG-BBBB or HHHH-BBBB, and transform either event into an
identical set of information for the application.

It is clear from the first two quoted items above that the stack does
this by zeroing the upper 64 bits of the source address.  So the when
A's packet arrives at GGGG-BBBB on B, the ILNP stack there tells the
TCP layer, and through it the server application, that the packet has
arrived from:

   0000-AAAA

Now, for simplicity, I am going to assume something which is not
realistic for ILNP: that the application and stack in B will simply
reply to host A, without in any way checking that the host with
Identifier AAAA really has the Locator GGGG.  (That is a whole other
discussion.)

The server application in B, or perhaps it is just the TCP layer in
B, then responds with a SYN-ACK packet to what it sees as 0000-AAAA -
and the ILNP stack alters this address to add the only Locator it
knows for AAAA (actually, it doesn't know it really is AAAA's
Locator) so far:

   EEEE-AAAA

The ILNP stack somehow (I guess from its integration with the TCP
layer) recognises this as an "initial packet" and so it adds an ILNP
nonce.  Then the packet goes back to A, and the ILNP stack there
stores the nonce, zeroes the upper 64 bits of the source address, and
presents it to the TCP layer.

The TCP layer in A sends its second packet - an ACK - to B.  This is
internally addressed to 0000-BBBB, but the ILNP stack changes this to

  GGGG.BBBB

and sends it, without an ILNP nonce, again from EEEE.AAAA.

The ILNP stack in A could just as easily have decided, for some
reason, that it should send the packet to HHHH.BBBB instead, since
both these addresses are valid combinations of Locators and
Identifier for B.   It also could have sent the packet out the other
ISP link, from FFFF.AAAA.

For all four combinations of this, once the ACK packet arrives at B,
B's ILNP stack needs to pass it on to the TCP layer, with the source
address set to 0000.AAAA.  Then the TCP layer will regard the session
as open, and the server application will be able to accept higher
level protocol commands, and send back replies - all of which will go
without ILNP nonces.

Ran - do both A's ILNP stack and B's ILNP stack also send ICMP
packets to each other, secured by the nonce the received from the
other, to tell each other their full set of Locators?   I understand
each host's ILNP stack does this if its Locator changes.  A's ILNP
stack doesn't need this, since it just looked up B's Identifier and
Locators from B's FQDN.  However, B's ILNP stack has no idea what A's
other Locator(s) if any, are.  Is the ICMP message meant to be used
at session initiation, like this - or is it only to be used if a host
changes its Locators?

I don't recall from reading all your I-Ds where this is is described.
 Unless A's ILNP stack sends such an ICMP message, I think the only
way B's ILNP stack could find out about A's other Locator is
something quite onerous:

  1 - B's ILNP stack does a reverse DNS lookup of the IP address
      EEEE-AAAA.

  2 - Assuming the ISP which provides A with the EEEE /64 address
      is running its reverse DNS correctly, then this should return
      A's FQDN.

         !!! This seems like a tall order - for A's network to
             ensure that both its ISP's update their reverse DNSes
             for every host in the network.  IF A's network is the
             only customer using the EEEE /64, then perhaps this
             network could run the reverse DNS for this /64, and
             likewise for the FFFF /64.  But if these ISPs had any
             other customers on these /64s, this wouldn't be possible
             and it would be necessary for the ISP's own reverse
             DNS to be securely updated by each such customer,
             to install a unique FQDN for each ILNP host.  This is
             in addition to each network separately ensuring that
             its ordinary DNS has an entry for each of its hosts,
             with the ILNP records as required.

  3 - B's ILNP stack does a DNS lookup of A's FQDN and so reliably
      obtains A's Identifier and two Locators.

That's enough questions for now.

To be continued.

   - Robin

---

From: Tony Li <[email-masked]>
Date: Mon, 12 Jul 2010 09:13:47 -0700

Hi Robin,

Your assumption and definition of "won't work" with ILNP is incorrect.

An application that specifies an address (and not a FQDN) can perform initial packet exchanges while the stack does a reverse name lookup followed by a forward lookup.

Note that this can be done in parallel with the initial exchange, so this introduces no latency.  Further, the results can be locally cached.

Finally, if the lookups do not succeed, the application is still effectively a legacy v6 application.  Since data is being transferred by the transport as requested, this constitutes 'working'.

Regards,
Tony

---

From: Robin Whittle <[email-masked]>
Date: Tue, 13 Jul 2010 13:59:55 +1000

Hi Tony,

Before I respond to your reply, I want to ask again some questions
from my first message:

When an application does a DNS lookup of an FQDN via the ILNP stack,
and the stack receives the results and finds ID and L64 records (I am
ignoring ILNPv4, LP records etc. for simplicity) does the stack
return the IP address to the application with the upper 64 bits zeroed?

How does the ILNP stack in B find out about all of A's Locators?  I
asked:

   Ran - do both A's ILNP stack and B's ILNP stack also send ICMP
   packets to each other, secured by the nonce the received from the
   other, to tell each other their full set of Locators?   I
   understand each host's ILNP stack does this if its Locator
   changes.  A's ILNP stack doesn't need this, since it just looked
   up B's Identifier and Locators from B's FQDN.  However, B's ILNP
   stack has no idea what A's other Locator(s) if any, are.  Is the
   ICMP message meant to be used at session initiation, like this -
   or is it only to be used if a host changes its Locators?

You wrote:

> An application that specifies an address (and not a FQDN) can
> perform initial packet exchanges while the stack does a reverse
> name lookup followed by a forward lookup.

Is this mentioned in the ILNP I-Ds?

Referring to my example, let's say B is running a web server and A a
web client.  In my original example, the web client started the
session with B's FQDN.  Here I will explore your explanation of A's
application starting with an IP address for B.

So this could be an example of a referral from D.  Let's say an
application in D knew B's IP address GGGG-BBBB.  D has no ILNP stack,
and the application in D must be able to work in an ordinary IPv6
fashion with the server in D, though I haven't yet figured out all
the details.  Somehow, an application in D communicates this
information to the web client application in A.

Alternatively, the server in D gives its own IPv6 address to A via
some direct or circuitous means, or there is a URL in some web-page
which does the same thing.  (e.g. Google cache results using numeric
IP address URLs - and D is the server for those cached results.)

So the application in A opens a socket ready to start a TCP session
with B's port 80, via B's IP address:

  GGGG-BBBB

The ILNP stack doesn't know whether the host at the above address has
an ILNP stack or not.  The ILNP stack sends the initial SYN packet to
this address, with a source address of:

  EEEE-AAAA

because I have assumed that this is the address A uses for IPv6
purposes - one of the two it has from its two ISPs, the other being
FFFF-AAAA.

The ILNP stack recognises this as an initial packet, and I assume it
attaches an ILNP nonce to it.

But how does A's ILNP stack know to do this?  If it doesn't attach an
nonce, B will never know that A is an ILNP host.  Then, the
communication session will be stuck in IPv6 mode - meaning that ILNP
doesn't provide any benefits for a session which begins with an IP
address - that ILNP only works for sessions which begin with a DNS
lookup of an FQDN.

Page 7 of draft-rja-ilnp-nonce-03 has the relevant material:

    If the initiator supports the I/L Split mode and from DNS data
    learns that the responder also supports the I/L Split mode, then
    the initiator MUST generate an unpredictable nonce value, MUST
    store that value in a local session cache, and MUST include the
    Nonce Destination Option in its initial packet(s) to the
    responder.

But how is the ILNP stack in A to know it should send a nonce with
this packet?

It can't very well delay the packet, do a reverse lookup on B's IP
address, find B's FQDN, do a lookup on that and if the reply
contains ID and L64 records, then send the packet with a nonce.

Yet if the ILNP stack in A sends a nonce with every initial packet to
an IP address which doesn't match anything in its cache, then doesn't
this add to the length of every initial packet?  Theoretically,
the routing system and destination IPv6 hosts should not be affected
by the nonce destination option, but it is an extra burden on the
packet and reduces its maximum payload.

Also, in a plain UDP protocol, initiated from a FQDN with DNS lookup,
to an ILNP destination host, assuming the stack somehow does correctly
discern each "initial packet" to a given destination and attach a
nonce to it, what happens if the initial packet is dropped but that a
second or subsequent packet (without a nonce) was received?

The destination host's ILNP stack would never see the nonce, and would
have to assume the initiating host was not an ILNP host.  I think this
would make support for ILNP multihoming, mobility and TE quite
unreliable with UDP protocols.  At least with TCP, the stack has a
good chance of identifying an "initial" packet, and attaching a
different nonce to subsequent SYN packets to the same destination, on
the reasonable assumption that one of these subsequent packets might
be the first to be received.

Back to the example:

The ILNP stack in B recognises the nonce, establishes the appropriate
session state and stashes it there.

But what information does the ILNP stack in B give its TCP layer about
the packet from A?  As far as I can understand, from reading all the
ILNP I-Ds, the ILNP stack recognises that A is an ILNP host, and would
therefore zero the upper 64 bits of the source address of the packet to

  0000-AAAA

before passing it to the TCP layer.  Is this correct?

I will assume this happens.  Next the TCP layer sends back a SYN-ACK
- with its specification of the destination address being 0000-AAAA.

The ILNP stack will send out the packet with a destination address of:

  EEEE-AAAA

since at present, EEEE is the only Locator the stack knows for the
Identifier AAAA.  (Actually, B has no way of knowing yet whether EEEE
really is a valid Locator for AAAA, but that is for a later discussion.)

The ILNP stack in B could send this SYN-ACK packet via either of its
two ISP links. Here I will assume it uses the link which has the GGGG
/64.  The ILNP stack in B also attaches an ILNP nonce to this packet.

So the packet is:

  Destination EEEE-AAAA
  Source      GGGG-BBBB
  With nonce
  SYN-ACK

A's stack receives this, passes it to the TCP layer as:

  Source      0000-BBBB

Is this correct?  In my previous message I quoted two passages from
the I-Ds which made me think the ILNP stack, for ILNP sessions,
always zeroes the upper 64 bits when passing the packet to the
transport layer - TCP in this case.

But the transport layer - and/or the application above it - won't
accept the SYN-ACK packet in this form, since the source address does
not match the destination address with which it send the SYN:

  EEEE-AAAA.

Please clarify how the ILNP stacks behave to this point, and I will
continue the example in a future message.

  - Robin

> Note that this can be done in parallel with the initial exchange,
> so this introduces no latency. Further, the results can be locally
> cached.
>
> Finally, if the lookups do not succeed, the application is still
> effectively a legacy v6 application. Since data is being
> transferred by the transport as requested, this constitutes
> 'working'.

---

From: Tony Li <[email-masked]>
Date: Mon, 12 Jul 2010 22:46:05 -0700

Hi Robin,

> return the IP address to the application with the upper 64 bits zeroed?

This is an implementation question, and there are various different alternatives.  I can conceive of several different implementation strategies, all of which seem equally valid at this point.  Assuming a BSD sockets based implementation:

a) Pass back any valid v6 address.  When the socket is opened, index into the locator cache and determine the locators and ID from the address.

b) Pass back a pointer/index/handle to the record in the locator cache.  Play fun games to ensure that the locator cache entry is still valid.  Lie to the application in telling it that it is a v6 address.  Might mess up applications that feel the urge to print the v6 address.  Breaks my heart not at all.  ;-)

c) Pass back a pointer/index/handle to a FQDN cache in the stack.  Only do the DNS lookup when the socket is opened.

That's two minutes of thought. 

Other stacks are not BSD sockets based, such as Cisco's IOS.  There all sorts of strange things could happen.  ;-)

And having a name oriented stack would be the best solution.

I was trying to reply to the rest of this, but gave up.  It was all implementation detail.

Tony

---

From: Robin Whittle <[email-masked]>
Date: Tue, 13 Jul 2010 17:59:03 +1000

Short version:    Despite me writing two detailed examples
                  with questions, Tony has not provided any
                  explanation of how an ILNP stack could work
                  with IPv6 applications - to support ordinary
                  operation with such applications in non-ILNP
                  hosts while also providing all ILNP's benefits
                  when working with such applications in ILNP-
                  equipped hosts.

                  Rather than me work on long examples with
                  detailed questions which Tony generally doesn't
                  answer, I suggest that he either agree with the
                  statement that ILNP can't work with ordinary
                  IPv6 applications - or that he show in detail
                  exactly how it would work.

                  Tony also wrote:

                  > a name oriented stack would be the best solution.

                  So I asked him what he thinks of Christian
                  Vogt's Name Based Sockets architecture, which
                  does exactly this - but would require radical
                  rewriting of many applications and major changes
                  to many of the protocols they use.

Hi Tony,

Thanks for your reply to one of my questions:

> This is an implementation question, and there are various different
> alternatives.  I can conceive of several different implementation
> strategies, all of which seem equally valid at this point. Assuming
> a BSD sockets based implementation:
>
>    a) Pass back any valid v6 address. When the socket is opened, index
>       into the locator cache and determine the locators and ID from
>       the address.

"Any valid IPv6 address" isn't clear.  Do you mean any random
address, or do you mean one of the addresses formed by a Locator
and the Identifier?

I don't see how this could work, or be compatible with the text
in the I-Ds which indicate that the upper 64 bits of addresses
should be zeroed.

So this is not an explanation.

>    b) Pass back a pointer/index/handle to the record in the locator
>       cache.  Play fun games to ensure that the locator cache entry
>       is still valid.  Lie to the application in telling it that it
>       is a v6 address.  Might mess up applications that feel the
>       urge to print the v6 address.  Breaks my heart not at all. ;-)

This is obviously not a solution.  Your disregard for ILNP
incompatibility with existing IPv6 applications is duly noted.

>    c) Pass back a pointer/index/handle to a FQDN cache in the stack.
>       Only do the DNS lookup when the socket is opened.

This is like b) - returning an artificial number as a result of a
DNS.

You would need to do this for all newly opened sockets - since
you don't know whether the socket will be for an ILNP host or
not.  Lookups of FQDNs such as with getaddrinfo() can return
multiple IP addresses, with a linked list of addrinfo
structures.  This c) approach obviously can't work, since you
don't even know how many pointers to return as if they are IP
addresses, since you haven't yet done the lookup.

None of what you write above is helpful to someone who wants to
understand how an ILNP stack would work, in its most basic
sense - supporting ordinary IPv6 applications in their
communications with IPv6 and or ILNP hosts which are also
running ordinary applications.

> That's two minutes of thought.

It appears that this is the first time you have considered this
- I had assumed you and Ran had already gone through it so you
were sure ILNP could work with ordinary IPv6 hosts, as you both
claim it does.

> Other stacks are not BSD sockets based, such as Cisco's IOS.
> There all sorts of strange things could happen. ;-)

Sure - I was trying to devise the most minimal, conducive,
example of ILNP stack operation to try to figure out how it
would work.

> And having a name oriented stack would be the best solution.

OK - so you believe ILNP is not the best solution.

What do you think of Christian Vogt's Name Based Sockets
architecture?  That requires substantially rewritten
applications.

> I was trying to reply to the rest of this, but gave up. It was all

It was my attempt to understand how ILNP would work - and the
more I looked at it, the more I doubted it could work.

Your inability to provide any explanation of how it could work -
and your lack of care about compatibility with many IPv6
applications - makes me even more inclined to think that no-one
has ever tried to figure out how to make ILNP work with IPv6
sockets, and that in fact it can't.

Rather than me doing lots of work on examples with questions
which you generally don't answer, please consider this:

  The ILNPv6/v4 stack can't support all, or anything like all,
  existing IPv6/v4 applications - to allow them to operate
  normally with non-ILNP hosts, while also enabling them to
  work properly with such applications in ILNP-equipped hosts,
  to achieve the benefits: multihoming, mobility and TE.

If you agree, then that's fine.  To me and pretty much
everyone else, that your understanding of ILNP is completely
at odds with what most people consider deployable.

If you disagree, then please provide some examples, with details
comparable to my examples, of exactly how the ILNP stack would
support existing IPv6 applications.

  - Robin

---

From: Tony Li <[email-masked]>
Date: Tue, 13 Jul 2010 01:18:17 -0700

I'm tired and I'm going to bed.

Tony