A follow-up on using multiple instances of rtpproxy. I finally got this to work, although I had to look at a lot of source code and contradictory (and terse) bits of documentation and finally experiment a while. So here is what I would consider "real" documentation on how to use these functions and features of both SER and rtpproxy in one place.
Although not a requirement to make this work, I'll mention my hardware platform configuration is a Dell 2950 III 48V DC-powered unit with a single four-core processor. The second CPU socket is empty. FreeBSD reports:
CPU: Intel(R) Xeon(R) CPU E5430 @ 2.66GHz (2665.33-MHz K8-class CPU) Origin = "GenuineIntel" Id = 0x10676 Stepping = 6 Features=0xbfebfbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE, MCA,CMOV,PAT,PSE36,CLFLUSH,DTS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE> Features2=0xce3bd<SSE3,RSVD2,MON,DS_CPL,VMX,EST,TM2,SSSE3,CX16,xTPR, PDCM,DCA,<b19>> AMD Features=0x20100800<SYSCALL,NX,LM> AMD Features2=0x1<LAHF> Cores per package: 4
I run rtpproxy in the two-interface mode, which from previous messages here I have found that I must be the only person who does, but I do have several good reasons for doing so.
I also recently reported a coding bug in rtpproxy that at least prevents the two-interface mode from working properly. The fix I came up for rtpproxy is: (diff -u this time, since apparently some OSes "patch" program can't cope with diff -c)
--- main.c.STOCK 2008-02-20 18:51:44.000000000 +0000 +++ main.c 2009-03-25 20:31:34.000000000 +0000 @@ -930,7 +940,7 @@ * cannot be trusted and address is different from one * that we recorded update it. */ - if (spa->untrusted_addr == 0 && !(spa->addr[pidx] != NULL && + if (spa->untrusted_addr[pidx] == 0 && !(spa->addr[pidx] != NULL && SA_LEN(ia[0]) == SA_LEN(spa->addr[pidx]) && memcmp(ia[0], spa->addr[pidx], SA_LEN(ia[0])) == 0)) { rtpp_log_write(RTPP_LOG_INFO, spa->log, "pre-filling %s's address " @@ -940,7 +950,7 @@ spa->addr[pidx] = ia[0]; ia[0] = NULL; } - if (spa->rtcp->untrusted_addr == 0 && !(spa->rtcp->addr[pidx] != NULL && + if (spa->rtcp->untrusted_addr[pidx] == 0 && !(spa->rtcp->addr[pidx] != NULL && SA_LEN(ia[1]) == SA_LEN(spa->rtcp->addr[pidx]) && memcmp(ia[1], spa->rtcp->addr[pidx], SA_LEN(ia[1])) == 0)) { if (spa->rtcp->addr[pidx] != NULL)
My setup is a bit more complicated than probably typical, so if you don't use two interfaces, simply use the one-interface invocation of rtpproxy ("-l oneipaddr") and build up your additional IP addresses as needed. You will see more on this in a moment.
Each rtpproxy process needs its own IP address(es) to bind to for RTP traffic, so you will need to alias multiple IP addresses on the same ethernet interface or use multiple interfaces. In my case, I put multiple IP address for each side of the rtpproxy instances on the same physical interface using "ifconfig interface-name alias" commands.
I chose to use multiple IP addresses on the same physical interface because I find that on this system I can't move more than about 40Mbit/sec per interface on a single rtpproxy instance before the processor core is at 85% utilization, so four should max-out around 160Mbit/sec, still well below the capacity of a single gigabit ethernet interface. Depending on your CPU speeds and maker as well as the system bus and ethernet card type you are using, your numbers will vary. That may mean buying plug-in cards rather than using the interfaces that happen to be on the motherboard (which frequently are slower, interrupt intensive and generally inefficient compared to others you can install).
The commands to put multiple IP addresses on the same interface would be like this on BSD and similar systems: (IP addresses are altered)
ifconfig em4 10.5.6.7 netmask 255.255.255.192 ifconfig em4 alias 10.5.6.8 netmask 255.255.255.255 ifconfig em4 alias 10.5.6.9 netmask 255.255.255.255 ifconfig em4 alias 10.5.6.10 netmask 255.255.255.255
and so on. Aliases in the same netblock as the non-aliased IP address normally have a 255.255.255.255 netmask, at least in the BSD world. FreeBSD lets you do this in /etc/rc.conf like this:
ifconfig_em4="inet 10.5.6.7 netmask 255.255.128.0" ifconfig_em4_alias0="inet 10.5.6.8 netmask 255.255.255.255" ifconfig_em4_alias1="inet 10.5.6.9 netmask 255.255.255.255" ifconfig_em4_alias2="inet 10.5.6.10 netmask 255.255.255.255"
(If you are running Linux, the way you do aliased IP addresses is probably different.) On FreeBSD, the result looks like:
(our inside network) ifconfig -a ... em4: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500 options=1b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING> inet 10.5.6.7 netmask 0xffffffc0 broadcast 10.5.6.63 inet 10.5.6.8 netmask 0xffffffff broadcast 10.5.6.8 inet 10.5.6.9 netmask 0xffffffff broadcast 10.5.6.9 inet 10.5.6.10 netmask 0xffffffff broadcast 10.5.6.10 ether 00:15:17:5b:xx:xx media: Ethernet autoselect (1000baseTX <full-duplex>) status: active
(public Internet side, built with similar commands) em5: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 options=1b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING> inet 66.1.2.3 netmask 0xffffffc0 broadcast 66.1.2.63 inet 66.1.2.4 netmask 0xffffffff broadcast 66.1.2.4 inet 66.1.2.5 netmask 0xffffffff broadcast 66.1.2.5 inet 66.1.2.6 netmask 0xffffffff broadcast 66.1.2.6 ether 00:15:17:5b:xx:xx media: Ethernet autoselect (1000baseTX <full-duplex>) status: active ...
Now that you have some IP addresses defined, start several instances of rtpproxy each listening for instructions on at least a different port than the other instances, as in:
(As found in /etc/rc.local - non BSD systems may need this elsewhere, but this needs to be ahead of where ser is started and after the interfaces get their IP addresses.)
/usr/local/bin/rtpproxy -F -s udp:127.0.0.1:8001 -l 66.1.2.3/10.5.6.7 /usr/local/bin/rtpproxy -F -s udp:127.0.0.1:8002 -l 66.1.2.4/10.5.6.8 /usr/local/bin/rtpproxy -F -s udp:127.0.0.1:8003 -l 66.1.2.5/10.5.6.9 /usr/local/bin/rtpproxy -F -s udp:127.0.0.1:8004 -l 66.1.2.6/10.5.6.10
CAUTION: There are probable security issues with using public IP addresses for the rtpproxy control address, so avoid doing that. (rtpproxy will take instructions from anybody who can get to the port and knows how to talk to it, or might just send it junk and crash that process. If you must use a public IP, block external access to the port range that is used to control rtpproxy.)
Once running, reference those rtpproxy processes via a line like this in ser.cfg:
modparam("nathelper", "rtpproxy_sock", "udp:127.0.0.1:8001=1 udp:127.0.0.1:8002=1 udp:127.0.0.1:8003=1 udp:127.0.0.1:8004=1")
That's all on one line. You will need to comment-out the existing nathelper line that uses the AF_UNIX socket to communicate with just the one copy of rtpproxy. If you still have the old AF_UNIX rtpproxy running, kill it.
The "=1" part of the modparam is the weighting, and can be handy if some of the rtpproxy processes are running on a different computer that is faster or slower than the local one or others. If all on the same computer, they should all be equal.
The documentation on the weighting control is unusually weak (even by SER documentation standards), so I can't tell you exactly how the weighting control works, what ranges of values are valid (or if they can be floating point), or the total number of weights should add up to a total value, or if it is simply a round-robin distribution, where a "1" says the next call goes to this rtpproxy before advancing to the next rtpproxy instance, while a "2" says the next two calls go here before advancing, and so on. I'm using all "1" values for the local system and it seems to be balancing more or less evenly, so for other choices you will need to experiment.
Once running for a while, you should see something like this in "top"
PID USERNAME THR PRI NICE SIZE RES STATE C TIME WCPU COMMAND 2207 xxxxxxxx 1 8 0 4180K 1056K nanslp 1 17.5H 27.05% rtpproxy 2208 xxxxxxxx 1 8 0 4192K 1068K nanslp 2 17.5H 26.66% rtpproxy 2206 xxxxxxxx 1 102 0 4204K 1080K RUN 3 17.4H 25.29% rtpproxy 2205 xxxxxxxx 1 8 0 4228K 1104K nanslp 0 17.3H 19.92% rtpproxy
You should now also see in tcpdump/ngrep output that the SDP payloads have different IP addresses in them for the rtpproxy that is handling the given call. Based on limited experience so far, starting more rtpproxy instances on a machine than there are total processors/cores available doesn't seem to do anything bad, but I would think it would be less efficient than having the numbers of rtpproxy equal to or less than available CPUs.
I did not mess with any of the mechanisms SER offers that can force a given call to a given instance. Such a thing might be useful if you want to guarantee a higher level of stability in packet forwarding or if some of the instances were functionally different. In my case, all instances of rtpproxy have the same capabilities.
Good luck!
Frank Durda IV http://nemesis.lonestar.org Copyright 2009, ask before reprinting.