Module: sip-router Branch: master Commit: ead9f3f966aa62be64d0c85df958a3ddc574f5c5 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=ead9f3f9...
Author: Marius Zbihlei marius.zbihlei@1and1.ro Committer: Marius Zbihlei marius.zbihlei@1and1.ro Date: Fri Jan 15 18:56:29 2010 +0200
Improved multihomed performance
The mhomed implementation works by calling a socket()/connect()/getsockname()/close() to find out the interface in a multihomed system. Because mhomed works only for UDP sockets, a major performance improvement is shown if we use the same socket for multiple connect()s, thus completly removing the socket() call and the close() call.
The CPU load(user+system) shown in a mhomed environment on a stateless router, with a call rate of 6000 calls/s is 46.1% load in the case of this patched version, versus 63.54% load in the case of the original version.
---
forward.c | 44 ++++++++++++++++++++++++++++++++++++-------- 1 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/forward.c b/forward.c index b124d36..c81e95a 100644 --- a/forward.c +++ b/forward.c @@ -110,10 +110,14 @@ /* return a socket_info_pointer to the sending socket; as opposed to * get_send_socket, which returns process's default socket, get_out_socket * attempts to determine the outbound interface which will be used; - * it creates a temporary connected socket to determine it; it will + * it uses a temporary connected socket to determine it; it will * be very likely noticeably slower, but it can deal better with * multihomed hosts */ + +static int sock_inet = 0; +static int sock_inet6 = 0; + struct socket_info* get_out_socket(union sockaddr_union* to, int proto) { int temp_sock; @@ -126,33 +130,57 @@ struct socket_info* get_out_socket(union sockaddr_union* to, int proto) LOG(L_CRIT, "BUG: get_out_socket can only be called for UDP\n"); return 0; } - - temp_sock=socket(to->s.sa_family, SOCK_DGRAM, 0 ); - if (temp_sock==-1) { - LOG(L_ERR, "ERROR: get_out_socket: socket() failed: %s\n", - strerror(errno)); + + switch(to->s.sa_family){ + case AF_INET : { + if(sock_inet <= 0){ + sock_inet = socket(AF_INET, SOCK_DGRAM, 0); + if (sock_inet==-1) { + LM_ERR("socket() failed: %s\n", strerror(errno)); + return 0; + } + } + temp_sock = sock_inet; + break; + } + case AF_INET6 : { + if(sock_inet6 <= 0){ + sock_inet6 = socket(AF_INET6, SOCK_DGRAM, 0); + if (sock_inet6==-1) { + LM_ERR("socket() failed: %s\n", strerror(errno)); + return 0; + } + } + temp_sock = sock_inet6; + break; + } + default: { + LM_ERR("Unknow protocol family \n"); return 0; } + } if (connect(temp_sock, &to->s, sockaddru_len(*to))==-1) { LOG(L_ERR, "ERROR: get_out_socket: connect failed: %s\n", strerror(errno)); + sock_inet = 0; + sock_inet6 = 0; goto error; } len=sizeof(from); if (getsockname(temp_sock, &from.s, &len)==-1) { LOG(L_ERR, "ERROR: get_out_socket: getsockname failed: %s\n", strerror(errno)); + sock_inet = 0; + sock_inet6 = 0; goto error; } su2ip_addr(&ip, &from); si=find_si(&ip, 0, proto); if (si==0) goto error; - close(temp_sock); DBG("DEBUG: get_out_socket: socket determined: %p\n", si ); return si; error: LOG(L_ERR, "ERROR: get_out_socket: no socket found\n"); - close(temp_sock); return 0; }