Chapter 4. From Single to Multinode

A mobile network with a single tower is infinitely more useful than one with zero towers. However, there comes a point where no matter how well that single tower is tuned, it cannot effectively cover a given area.


Because OpenBTS uses the same software stack to implement large and small coverage areas and has even been made to run on a Raspberry Pi, try to free your mind of the classic “cell tower” image. A tower could easily fit in a shoebox or blend in with your WiFi access point.

This chapter describes how to expand your network to multiple physical sites but still maintain a single logical network. This logical network will support Mobility and Handover as any commercial network would.

Mobility, Handover, and Roaming

There is some confusion among these terms. While they do mean very specific things, even experts in the field will throw them around in discussion and expect the other party to understand the correct meaning from the context. To clear up this ambiguity each term will be outlined briefly.


Mobility is the ability of a handset to receive service on different physical base stations in an operator’s network. As the handset moves in three-dimensional space, the signal quality it receives from neighboring base stations will fluctuate. When the handset detects a significantly better signal from a neighboring base station, it sends an LUR to register or “camp” to the new base station. To differentiate, a periodic LUR at the same base station is refreshing an existing registration but an LUR at a new base station is recamping, switching the registration to a new tower.


An LUR is not performed unless the two base stations have different location area codes (LACs). In a traditional GSM network, all base stations in a given geographic region have the same LAC. However, OpenBTS currently requires all base stations to have a unique LAC so LURs will be performed when moving in between base stations. This triggers an updated SIP REGISTER message and, thus, an updated subscriber registry entry containing the IP of the new base station.

Mobility is a function of the network but the handset makes the decision to recamp. Also, it is also only possible when the handset is not in an active transaction such as a voice call or exchanging SMS. Mobility may also be referred to as “idle mode recamping.”


Handover is the ability of an active voice call to survive the transition between two base stations. Mobility is a prerequisite for Handover, but unlike Mobility, the network determines and executes Handover. The handset has no choice but to obey Handover commands that the network has sent it.

The Base Station Controller (BSC) controls Handover in a traditional GSM network. OpenBTS eliminates the need for a BSC through the use of a new peer-to-peer protocol. Information about neighboring frequencies, identities, and active transactions is exchanged over this protocol, simplifying the deployment architecture.

Several factors determine the decision to execute a Handover. First, the downlink signal from the base station currently serving the handset must be sufficiently weak. Also, the signal from the strongest neighboring base station must also exceed the serving base station level by a set threshold. Finally, the strongest neighboring base station must not have recently rejected any Handovers due to congestion. If these conditions are met, the serving base station will initiate a Handover to the strongest neighboring base station.


Roaming is Mobility across carriers. It requires an administrative agreement between those carriers and common interface technology, usually GSM-Mobile Application Part (MAP) signaling across the Signaling System No. 7 (SS7) network. It is impossible to roam within your own network.


Up until now, you have been building a “network-in-a-box” topology with every single component located on a single server, a single logical entity. In a multinode network there are now two logical entities: Central Services and the “tower.” The components you are familiar with so far must be rearranged a bit to support this. Central Services will need SIPAuthServe, SMQueue, and Asterisk installed. For the sake of simplicity, SIPAuthServe, SMQueue, and Asterisk will be referred to as Central Services for the remainder of this chapter. The tower will only run OpenBTS.

There will be a single Central Services install and multiple tower installs as shown in Figure 4-1.

Multinode topology
Figure 4-1. Multinode topology

Towers are backhauled over IP to Central Services, allowing multiple coverage areas to share the same subscriber database and configuration.

In the following instructions, Central Services will be located at and towers will start at

Central Services Setup

Instead of extracting Central Services from your existing network-in-a-box configuration, it’s easier to just move the OpenBTS instance and radio hardware to a new home. This avoids having to transplant the subscriber data and configurations for SMQueue, SIPAuthServe, and Asterisk.

Remove OpenBTS

To make sure OpenBTS doesn’t start on boot and continually fail because it’s missing a radio, uninstall it now:

$ sudo apt-get remove openbts

Configure Logging

Each tower independently, as well as Central Services, will generate logging information. You need to set up Central Services to accept logging information from all towers so all activity across the network can be captured in a single file.

This step is not necessary to establish a functional multinode network but is extremely useful when debugging. Tracking down errors across multiple towers with separate logs is not very much fun.

Edit /etc/rsyslog.conf with your favorite editor and uncomment the two lines directly after “provides UDP syslog reception”:

# provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514

These two lines mean that rsyslog will accept UDP log traffic on port 514. To apply these settings, a restart of the service is needed:

$ sudo service rsyslog restart

Asterisk, SMQueue, and SIPAuthServe

There is nothing to reconfigure in these components. They don’t care if the OpenBTS instance is communicating locally or across an IP network.

Tower Setup

Jump back to Operating System and Development Environment Setup and follow along on a new virtual machine or fresh server to get your new tower’s OS and components up and running. Make sure to pick a unique hostname for the tower so it’s distinguishable in the centralized logs. Also, save some time at the end of those instructions by only installing OpenBTS.

These instructions assume that both your tower and Central Services machines are located on the same network subnet. Once you log in to the new tower installation, make sure you can ping Central Services (press Ctrl-C to stop the ping command):

$ ping
PING ( 56(84) bytes of data.
64 bytes from icmp_req=1 ttl=128 time=4.28 ms
64 bytes from icmp_req=2 ttl=128 time=4.34 ms
64 bytes from icmp_req=3 ttl=128 time=4.48 ms
64 bytes from icmp_req=4 ttl=128 time=4.48 ms
--- ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3006ms
rtt min/avg/max/mdev = 4.285/4.399/4.484/0.086 ms

Configure SIP Proxies

OpenBTS connects to all other components using SIP. Now that these components are on another host, the SIP.Proxy key needs to be adjusted accordingly. Also, now that OpenBTS is speaking to services on IP addresses other than localhost, it needs to know what address to send its own requests to. The SIP.Local.IP key allows you to set the IP address that other services should use when contacting OpenBTS or replying to its requests. Set it now using your tower’s IP address:

OpenBTS> config SIP.Local.IP
SIP.Local.IP changed from "" to ""
SIP.Local.IP is static; change takes effect on restart

Restart OpenBTS to apply this static key:

$ sudo stop openbts
$ sudo start openbts

Now, each SIP.Proxy key can be updated to point to Central Services, so registration, voice, and SMS traffic are sent there instead of to localhost:

OpenBTS> config SIP.Proxy.Registration
SIP.Proxy.Registration changed from "" to ""
OpenBTS> config SIP.Proxy.SMS
SIP.Proxy.SMS changed from "" to ""
OpenBTS> config SIP.Proxy.Speech
SIP.Proxy.Speech changed from "" to ""


Make sure to include the port information. Each component runs on a different port and routing requests to the incorrect port would break functionality.

Force a handset to register via this new topology to test things out. Voice and SMS should also function. Verify this before moving on.

Configure Logging

Logging information that each tower generates can be sent to Central Services. The logging daemon on Central Services has already been changed to accept this traffic; now it’s time to tell our tower nodes to send it.

Edit /etc/rsyslog.d/OpenBTS.conf with your favorite editor so it contains a new line directly below the existing local7 entry:

local7.*              /var/log/OpenBTS.log
local7.*              @the-central-services-ip

This line means that in addition to logging information to the OpenBTS.log file on disk, the same messages will also be sent to Central Services for logging there. To apply these settings, a restart of the service is needed:

$ sudo service rsyslog restart

Topology Reworked

So far your network is functionally the same. There is still one coverage area created with one logical tower and Central Services—they’ve just been split onto two separate physical machines. The next step involves adding additional neighboring towers to the network and configuring them to appear as a single RAN.

Adding Neighboring Towers

The tower setup section can now be repeated for as many physical towers as you’d like to add. Once they have been configured to at least function as an independent tower, they must be configured to behave as a proper neighboring tower within the network. Additionally, all existing towers must be informed about this new tower.

So far, assume that there is only one tower in your network—the one you just ported from the network-in-a-box layout. Take a look at its identity parameters now:

OpenBTS> config Identity
GSM.Identity.BSIC.BCC 2     [default]
GSM.Identity.BSIC.NCC 0     [default]
GSM.Identity.CI 10     [default]
GSM.Identity.LAC 1000     [default]
GSM.Identity.MCC 001     [default]
GSM.Identity.MNC 01     [default]
GSM.Identity.ShortName GroundControl

Of these parameters, some must be unique and others must be identical across all neighbors. Table 4-1 is a convenient summary. The configuration schema also embeds this information in the scope field. The scope field will tell you if the key must be unique or identical among neighboring towers or across all towers in your network.

Table 4-1. Configuration scope
Identical Unique










Some background information will be presented, so each parameter is understood, along with a step-by-step guide to setting up your next tower.

Must Be Identical

The GSM.Identity.MCC and GSM.Identity.MNC keys are the highest-level identification for any network, indicating what country this network is in and which carrier is running it. Regulatory bodies assign both of these IDs. Test networks always use 001 and 01, respectively. If this isn’t a test network, you will probably have paid money for a license and be very aware of the appropriate value.

The GSM.Identity.BSIC.NCC key is your Network Color Code (NCC), a piece of information that handsets use to very quickly determine if they can gain access to the network. All carriers in a given area must have unique color codes.

Related to the last key is GSM.CellSelection.NCCsPermitted. This key is used when working with partner networks to express the following: “not only is my NCC OK but these other NCCs are permitted.” The NCCsPermitted key is a bitwise flag, not an integer value. Regardless, all towers should have the same NCCsPermitted setting.

The GSM.Identity.ShortName key should be identical across all towers but it is not required to be. A convenient debugging technique when deploying a multinode network is to set unique shortnames for each tower. If your handset reliably shows the shortname, you now instantly know what tower your handset is camped to while moving around.


The step-by-step instructions for this section are pretty basic: make sure all of these keys are identical to the existing towers in your network.

Must Be Unique

The first key, GSM.Radio.C0, must be unique because it is the ARFCN and thus RF being used on this tower. If physically adjacent towers are using the same frequency, it will create interference and deny service to any participants in the overlapping signal region.


Not only do the C0 ARFCNs need to be unique, but they also must not be numerically adjacent. Because the signal spacing is only 200 KHz and the signal bandwidth is 270 KHz, adjacent ARFCNs overlap. Use at least every other ARFCN when deploying physically adjacent towers (e.g., tower 1 uses ARFCN 151 and tower 2 uses ARFCN 153).

The GSM.Identity.BSIC.BCC must also be unique for physically adjacent towers. It signals the Base Station Color Code (BCC), a 3-bit field allowing seven unique values.

Your licensed C0 ARFCNs and the BCC are very limited in number and a color map might be helpful in assigning values to towers if you plan on having a lot of them. A color map shows the geographic location of all towers and assigns each one a color. Each color corresponds to an ARFCN number and BCC pair as shown in Figure 4-2. If your planning shows that no two adjacent towers have the same “color,” then Mobility and Handovers will not be hindered by clashing ARFCNs or BCCs.

Color map
Figure 4-2. Color map

GSM.Identity.LAC must be unique across all towers in your network. As a handset moves across tower boundaries it realizes that the Location Area Code is changing and should perform another LUR. This LUR is translated into a SIP REGISTER, and SIPAuthServe can update the IP address for the tower where this handset is reachable. The requirement that the LAC be unique is specific to OpenBTS. Traditional networks have LACs that correspond to much larger geographic areas containing multiple towers.

GSM.Identity.CI is the Cell ID (CI) and must be unique across all towers in your network.


Assign a color to the new tower and use the corresponding C0 value and BCC:

OpenBTS> config GSM.Radio.C0 168
GSM.Radio.C0 changed from "151" to "168"
GSM.Radio.C0 is static; change takes effect on restart
OpenBTS> config GSM.Identity.BSIC.BCC 3
GSM.Identity.BSIC.BCC changed from "2" to "3"

As there are plenty of LAC and CI values, simply use the next one for each tower:

OpenBTS> config GSM.Identity.LAC 1001
GSM.Identity.LAC changed from "1000" to "1001"
OpenBTS> config GSM.Identity.CI 11
GSM.Identity.CI changed from "10" to "11"

Restart OpenBTS to apply the changes:

$ sudo stop openbts
$ sudo start openbts

Neighbor List and Command

Your towers are now configured so as not to stomp on each other either physically through their transmission frequencies or logically in their ID numbering schemes. They must still be told about each other in the configuration. This is accomplished using the GSM.Neighbors key. Each tower must have its GSM.Neighbors key set to a space-separated list of IP addresses corresponding to all physically adjacent towers but excluding itself.

On your new tower (, enter the following to tell it about your original tower (

OpenBTS> config GSM.Neighbors
GSM.Neighbors changed from "" to ""

Do the same for your original tower so it knows about the new tower:

OpenBTS> config GSM.Neighbors
GSM.Neighbors changed from "" to ""

Still on your original tower,, check out the neighbors command:

OpenBTS> neighbors
host                  C0  BSIC FreqIndex Noise ARFCNs TCH-Avail Updated Holdoff
------------------    --- ---- --------- ----- ------ --------- ------- ------- 168 2    0         68    1      7         16      0

The OpenBTS peering protocol automatically queries for information about the neighboring base stations defined in GSM.Neighbors. The neighbors command provides access to this information. Here you see the C0 ARFCN, current noise level, total ARFCN count, and available traffic channels (TCHs).

Neighbor-Enabled Commands

Now that you have a functional pair of neighbors, the chans command will also provide additional information during an active call. This information is related to the current reception level of the strongest neighboring tower that the handset reported. To see it, use the chans command with a –l flag:

OpenBTS> chans -l
CN TN chan  transaction LAPDm           recyc Signal RSSI RSSP SNR  FER   BER TA
      type  id          state                 dB     dB   dB        pct   pct sym
0  1  TCH/F T100        LinkEstablished false 26     -50  -24  38.7 0.00  0   0.9

                  TXPWR TA_DL RXLEV_DL BER_DL Time IMSI     Neighbor    Handover
                  dBm   sym   dBm      pct    M:S           ARFCN(dBm)  C0:BSIC
                  7     0     -93      2.26   0:25 2140...  168         (-76)

Coverage Overlap Tuning

With each tower tuned individually, the trickiest part is to tune them in relation to each other. Take a look again at Figure 4-1. The area of overlap between Tower 1 and Tower 2 is crucial. This area must be wide enough so that a handset traveling through it can contact both towers reliably for as long as it takes to perform a Handover. The terrain in this area must be taken into account as well as the potential handset velocity. The overlap must not be too excessive as to waste resources though. Finding this balance between reliable overlap and optimized overall coverage is key. Again, entire businesses can be built on this expertise and a deep dive falls outside the scope of a “getting started” book.

Handset Mobility only has a single key to configure: GSM.CellSelection.CELL-RESELECT-HYSTERESIS. This key indicates to the handset how much better a potential neighboring tower’s signal should be before it recamps.

OpenBTS can more directly control Handover. There are several keys available for tuning Handover behavior:

OpenBTS> config Handover
GSM.Handover.FailureHoldoff 20     [default]
GSM.Handover.Margin 15     [default]
GSM.Handover.Ny1 50     [default]
GSM.Timer.Handover.Holdoff 10     [default]

The GSM.Handover.Margin key is similar to GSM.CellSelection.CELL-RESELECT-HYSTERESIS except that it’s used for Handover operations. With both of these settings, it is important to remember that if they are set too high (e.g., the tower must be much stronger before switching), there is a risk that the handset will not jump over in time. If they are set too low (e.g., the tower must only be slightly stronger before switching), the network can be hit with a spike of traffic from handsets located in an area where both signals are approximately equal as the handsets rapidly jump back and forth.

Even more parameters are available with devconfig if you would like to experiment with the weights inside the OpenBTS Handover algorithm:

OpenBTS> devconfig Handover
GSM.Handover.FailureHoldoff 20     [default]
GSM.Handover.History.Max 32     [default]
GSM.Handover.Margin 15     [default]
GSM.Handover.Ny1 50     [default]
GSM.Handover.RXLEV_DL.History 6     [default]
GSM.Handover.RXLEV_DL.Margin 10     [default]
GSM.Handover.RXLEV_DL.PenaltyTime 20     [default]
GSM.Handover.RXLEV_DL.Target 60     [default]
GSM.Timer.Handover.Holdoff 10     [default]

Get Getting Started with OpenBTS now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.