[asterisk-dev] expensive call - ast_ouraddrfor()

Luigi Rizzo rizzo at icir.org
Tue Jul 17 17:12:52 CDT 2007


On Tue, Jul 17, 2007 at 02:56:52PM -0500, Kevin P. Fleming wrote:
> Luigi Rizzo wrote:
> > just noticed that chan_sip() does a number of calls to
> > ast_ouraddrfor(), which is used to determine the local
> > address to use when talking to a remote peer.
> 
> I have a magic plan for this... but have never had time to implement it.
> Partially that is because portions of the plan are Linux-specific, and

that isn't a big issue, as long as there is a common interface
(ast_ouraddfor() is more or less good enough) that hides the internals
of the implementation on different platforms.

This said i am not sure that the following is a particularly good idea:

> 3) For sockets that are bound to a wildcard address, chan_sip can use
> recvmsg() and cmsg() to find out what IP address each received packet
> was *received on*, and then open a direct socket for that IP address.
> That socket should be used for all further communication related to the
> sip_pvt that is involved with that packet (and be kept open until some
> error occurs that causes it to be closed).

because the risk is that you end up with 100's of open sockets,
one for each active dialog (and it's not just the number of descriptors,
is the fact that you need to poll() or select() on them, or have
one thread on each).

A bit of thinking led me to believe the following:

- unless you really have only a single IP,
  avoiding wildcard sockets solves the problem for connections started
  from remote peers, but not for those originated locally.
- Keeping a cache of recent ast_ouraddrfor() results (my original idea)
  is equally ineffective, as it only maps individual remote addresses,
  and on a busy server you might have way too many of them;
- What you really want here is do a route lookup, but i have no
  idea if there is any kernel interface that exposes such queries.

However, maybe the following works:

    - in a static config file define the addresses that belong to
      each subnet (meant as a set of mutually reachable addresses)
      you are connected to, e.g.

	subnet = lab 10.2.0.0/16 10.4.10.0/24
	subnet = staff 10.50.0.0/16
	subnet = dummy 192.168.0.0/24 10.0.0.0/8
	subnet = dummy 172.16.0.0/12
	subnet = local 169.254.0.0/16
	subnet = loopback 127.0.0.0/8
	subnet = world 0.0.0.0/0	; the default

    - store all these addresses in a data structure that allows longest
      prefix match (if the list is short as i suspect it is in most cases,
      even a simple array will suffice, you just scan all of it).

    - periodically (every few minutes, or on demand if you have signals
      telling you of an interface address change) grab all local
      interface addresses, and associate them to the various subnet
      names, using longest prefix match.

      If you have multiple addresses in the same subnet, you can presumably
      use any of them as they should be all reachable from the subnet.

    - replace ast_ouraddrfor() with a longest prefix match on the dst
      address, and return one of the local IP addresses associated with
      the entry.

    - additionally, if one or more of these subnet are behind a NAT, you
      you could even define an stun-addr for each of these subnet so
      you can run a proper transaction with the server to discover the
      externally-visible IP, e.g.

	stun-addr = world foo.stun.com:3478


What do you think ? Makes sense ?

	cheers
	luigi



More information about the asterisk-dev mailing list