add template-configs, script to launch network

This is the set of scripts I've written for myself over the years to easily
configure and run Osmocom core networks on my lab computer. I hope this will be
useful to others as well.
This commit is contained in:
Neels Hofmeyr 2018-08-22 17:32:21 +02:00
parent 693355ea35
commit 697a617e0e
20 changed files with 701 additions and 0 deletions

9
README
View File

@ -1,3 +1,12 @@
=== WHAT IS THIS?
* quickly build the entire Osmocom core network stack from source, with a
generated top-level makefile (see the rest of this README file below).
* quickly configure, launch and tear down an entire Osmocom core network on
your box (see net/README).
=== Quick Start
sudo apt install \

106
net/README Normal file
View File

@ -0,0 +1,106 @@
=== WHAT IS THIS?
* quickly configure, launch and tear down an entire Osmocom core network on
your box (see net/README).
This is the set of tools I wrote for myself and use every day to run and test
the Osmocom core network. I hope this helps, and I would appreciate
contributions of any improvements you may have!
=== Quick Start
cp config_2g3g config_mine
$EDITOR config_mine
# update IP addresses and device names as required
mkdir my_network
cd my_network
../cfg.sh ../config_mine ../tmpl_std
./run.sh
# Launches numerous x-terminals with one component running in each.
# Logs and pcap traces are being taken automatically.
# hit enter in the original first terminal to tear down all programs.
# Enter a name to save logs, otherwise all logging will be stored
# under autolog/<timestamp>
Then possibly modify the config and refresh:
# tweak config?
$EDITOR ../config_mine
../cfg.sh
# picks up same ../config_mine and ../tmpl_std from last time
# own templates?
cp -r ../tmpl_std ../tmpl_mine
$EDITOR ../tmpl_mine/*
../cfg.sh ../tmpl_mine
# picks up same ../config_mine from last time, and ../tmpl_mine from cmdline
=== Config file templates
A *directory* contains template files that are filled with specific values by the
cfg.sh script (aided by fill_config.py). See e.g. tmpl_std/.
A *file* contains local config items that are put into the templates. See e.g.
config_2g3g.
The cfg.sh script helps to fill the templates with the config values. Simply
invoke cfg.sh with a dir argument (templates dir) and a file argument (specific
config values).
If one or both are omitted, the script tries to re-use the most recent paths,
they were stored in local files '.last_config' and '.last_templates'.
The result is a complete set of .cfg files that match your local machine and
network config.
=== Launch
A run.sh script template (tmpl_std/run.sh) also gets filled with specifics and
placed next to the .cfg files.
run.sh uses sudo to start tcpdump, configure ip forwarding and masquerading
(for the GGSN's APN tunnel required for data services).
When you launch run.sh, many xterms are launched, and when hitting enter, all
of them get destroyed again. This is obviously intended to be run on your
desktop computer or laptop, not on a remote box. It may also make sense to
launch all of them in the current shell, and maybe or maybe not switch off
stderr logging; or to launch each component in a tmux window or whatnot -- if
you figure out something in that line, I would be glad to get contributions and
incorporate that.
=== Logging and pcaps
The run.sh script automatically stores all configs, logs and pcap traces in
./autolog/<timestamp> dirs. After closing the components (by hitting enter),
you may also enter a name for the logs, after which they are stored in
./logs/<name>. The idea is to keep all important logs with a name, and that you
can every now and then just 'rm -rf ./autolog' to make space.
=== 3G
You may notice that the templates include nano3G.txt files. These include a
convenient listing of commands to connect to an ip.access nano3G DMI and
connect it to the HNBGW as configured by the templates.
=== 2G BTS
At the time of writing, there are no osmo-bts.cfg files, since this is intended
for the core network and BSC components only. Feel free to add!
Typically you'd need to edit only the /etc/osmocom/osmo-bts.cfg to match your
IP address and ipa unit-id:
bts 0
oml remote-ip 192.168.0.123
ipa unit-id 1800 0

44
net/cfg.sh Executable file
View File

@ -0,0 +1,44 @@
#!/bin/sh
config_file=""
tmpl_dir=""
while test -n "$1"; do
arg="$1"
shift
if [ ! -e "$arg" ]; then
if [ -e "../$arg"]; then
arg="../$arg";
fi
fi
if [ -f "$arg" ]; then
if [ -n "$config_file" ]; then
echo "Error: more than one config file: '$config_file' and '$arg'"
exit 2
fi
config_file="$arg"
fi
if [ -d "$arg" ]; then
if [ -n "$tmpl_dir" ]; then
echo "Error: more than one template dir: '$tmpl_dir' and '$arg'"
exit 2
fi
tmpl_dir="$arg"
fi
done
if [ -z "$config_file" ]; then
config_file="$(cat .last_config)"
fi
if [ -z "$tmpl_dir" ]; then
tmpl_dir="$(cat .last_templates)"
fi
set -e
../fill_config.py "$config_file" "$tmpl_dir"
echo "$config_file" > .last_config
echo "$tmpl_dir" > .last_templates

23
net/common_logging Normal file
View File

@ -0,0 +1,23 @@
log stderr
logging filter all 1
logging color 1
logging print level 1
logging print category 1
logging print category-hex 0
logging print file basename
#logging print timestamp date
logging print extended-timestamp 1
logging level all debug
log file current_log/${_name}.log
logging filter all 1
logging color 1
logging print level 1
logging print category 1
logging print category-hex 0
logging print file basename
#logging print timestamp date
logging print extended-timestamp 1
logging level all debug
log gsmtap 127.0.0.1
logging filter all 1
logging level all debug

50
net/config_2g3g Normal file
View File

@ -0,0 +1,50 @@
ETH_DEV=eth0
APN_DEV=apn0
PUBLIC_IP="192.168.0.23"
PUBLIC_IP2="192.168.0.42"
MCC=001
MNC=01
HLR_IP="127.0.0.1"
MSC_PC="0.23.1"
SGSN_IP="${PUBLIC_IP}"
SGSN_PC="0.23.2"
SGSN_GB_PORT=23000
GBPROXY_IP="${PUBLIC_IP}"
GBPROXY_GB_PORT=7777
PCU_GB_PORT=23000
MGW4MSC_IP="${PUBLIC_IP}"
MGW4MSC_VTY_IP="127.0.0.1"
BSC_IP="${PUBLIC_IP}"
BSC_PC="0.42.0"
MGW4BSC_IP="${PUBLIC_IP2}"
MGW4BSC_PORT="12427"
MGW4BSC_VTY_IP="127.0.0.2"
HNBGW_PC="0.3.0"
HNBGW_IP="${PUBLIC_IP}"
GGSN_IP="${PUBLIC_IP2}"
GGSN_DNS0="192.168.0.1"
GGSN_DNS1="9.9.9.9"
GGSN_NET="192.168.42.0/24"
HNODEB_IP="192.168.0.124"
UARFCN=4357
SCRAMBLE=157
LAC=1${UARFCN}
RAC=11
HNODEB_IP2="192.168.0.23"
UARFCN2=4358
SCRAMBLE2=258
LAC2=2${UARFCN2}
RAC2=22

105
net/fill_config.py Executable file
View File

@ -0,0 +1,105 @@
#!/usr/bin/env python3
import os, sys, re, shutil
def get_arg(nr, default):
if len(sys.argv) > nr:
return sys.argv[nr]
return default
local_config_file = os.path.realpath(get_arg(1, 'local_config'))
tmpl_dir = get_arg(2, 'tmpl')
if not os.path.isdir(tmpl_dir):
print("Template dir does not exist: %r" % tmpl_dir)
exit(1)
print('using config file %r\non templates %r' % (local_config_file, tmpl_dir))
# read in variable values from config file
local_config = {}
line_nr = 0
for line in open(local_config_file):
line_nr += 1
line = line.strip('\n')
if not '=' in line:
if line:
print("Error: %r line %d: %r" % (local_config_file, line_nr, line))
exit(1)
continue
split_pos = line.find('=')
name = line[:split_pos]
val = line[split_pos + 1:]
if val.startswith('"') and val.endswith('"'):
val = val[1:-1]
if name in local_config:
print("Error: duplicate identifier in %r line %d: %r" % (local_config_file, line_nr, line))
local_config[name] = val
print('config:\n\n' + '\n'.join('%s=%r' % (n,v) for n,v in local_config.items()))
# replace variable names with above values recursively
replace_re = re.compile('\$\{([A-Za-z0-9_]*)\}')
command_re = re.compile('\$\{([A-Za-z0-9_]*)\(([^)]*)\)\}')
idx = 0
for tmpl_name in sorted(os.listdir(tmpl_dir)):
tmpl_src = os.path.join(tmpl_dir, tmpl_name)
dst = tmpl_name
local_config['_fname'] = tmpl_name
local_config['_name'] = os.path.splitext(tmpl_name)[0]
local_config['_idx0'] = str(idx)
idx += 1
local_config['_idx1'] = str(idx)
try:
result = open(tmpl_src).read()
except:
print('Error in %r' % tmpl_src)
raise
while True:
used_vars = set()
for m in command_re.finditer(result):
cmd = m.group(1)
arg = m.group(2)
if cmd == 'include':
include_path = os.path.join(tmpl_dir, arg)
if not os.path.isfile(include_path):
print('Error: included file does not exist: %r in %r' % (include_path, tmpl_src))
exit(1)
try:
incl = open(include_path).read()
except:
print('Cannot read %r for %r' % (include_path, tmpl_src))
raise
result = result.replace('${%s(%s)}' % (cmd, arg), incl)
else:
print('Error: unknown command: %r in %r' % (cmd, tmpl_src))
exit(1)
for m in replace_re.finditer(result):
name = m.group(1)
if not name in local_config:
print('Error: undefined var %r in %r' % (name, tmpl_src))
exit(1)
used_vars.add(name)
if not used_vars:
break
for var in used_vars:
result = result.replace('${%s}' % var, local_config.get(var))
with open(dst, 'w') as dst_file:
dst_file.write(result)
shutil.copymode(tmpl_src, dst)
# vim: ts=2 sw=2 expandtab

17
net/stale_config.sh Executable file
View File

@ -0,0 +1,17 @@
#!/bin/sh
stale="0"
for f in *.cfg; do
f="$(basename "$f")"
for g in $(find . -maxdepth 2 -name "$f" -or -name "common_logging") ; do
if [ "$f" -ot "$g" ]; then
stale="1"
echo "$f older than $g"
fi
done
done
if [ "$stale" = "1" ]; then
echo "Stale configs. Hit enter to continue anyway."
read ok_to_continue
fi

18
net/tmpl_std/nano3G.txt Normal file
View File

@ -0,0 +1,18 @@
ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -c aes128-cbc root@${HNODEB_IP}
telnet ${HNODEB_IP} 8090
set mcc="${MCC}"
set mnc="${MNC}"
set rfParamsCandidateList=({${UARFCN}, ${SCRAMBLE}, 1})
set lacRacCandidateList=({${LAC}, (${RAC})})
set hnbGwAddress="${HNBGW_IP}"
action 2061
action 1216
action establishPermanentHnbGwConnection
set csgAccessMode=CSG_ACCESS_MODE_CLOSED_ACCESS
set accessControlList = ({"901700000014701",1,"14701"})
set accessControlList = ({"901700000014701",1,"14701"},{"901700000014702",1,"14702"})
set csgAccessMode=CSG_ACCESS_MODE_OPEN_ACCESS

18
net/tmpl_std/nano3G2.txt Normal file
View File

@ -0,0 +1,18 @@
ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -c aes128-cbc root@${HNODEB_IP2}
telnet ${HNODEB_IP2} 8090
set mcc="${MCC}"
set mnc="${MNC}"
set rfParamsCandidateList=({${UARFCN2}, ${SCRAMBLE2}, 1})
set lacRacCandidateList=({${LAC2}, (${RAC2})})
set hnbGwAddress="${HNBGW_IP}"
action 2061
action 1216
action establishPermanentHnbGwConnection
set csgAccessMode=CSG_ACCESS_MODE_CLOSED_ACCESS
set accessControlList = ({"901700000014702",1,"14702"})
set accessControlList = ({"901700000014701",1,"14701"},{"901700000014702",1,"14702"})
set csgAccessMode=CSG_ACCESS_MODE_OPEN_ACCESS

87
net/tmpl_std/osmo-bsc.cfg Normal file
View File

@ -0,0 +1,87 @@
network
#meas-feed destination 172.18.18.18 8888
#meas-feed scenario foo23
network country code ${MCC}
mobile network code ${MNC}
encryption a5 1
bts 0
type sysmobts
band GSM-1800
location_area_code 23
cell reselection hysteresis 14
ip.access unit_id 1801 0
gprs mode gprs
gprs nsvc 0 remote ip ${GBPROXY_IP}
gprs nsvc 0 remote udp port ${GBPROXY_GB_PORT}
gprs nsvc 0 local udp port ${PCU_GB_PORT}
gprs nsvc 0 nsvci 1801
gprs nsei 1801
gprs cell bvci 1801
trx 0
rf_locked 0
arfcn 868
nominal power 23
max_power_red 20
timeslot 0
phys_chan_config CCCH+SDCCH4
timeslot 1
phys_chan_config SDCCH8
timeslot 2
phys_chan_config TCH/F
timeslot 3
phys_chan_config TCH/F
timeslot 4
phys_chan_config TCH/F
timeslot 5
phys_chan_config PDCH
timeslot 6
phys_chan_config PDCH
timeslot 7
phys_chan_config PDCH
bts 1
type sysmobts
band GSM-1800
location_area_code 42
cell reselection hysteresis 14
ip.access unit_id 1802 0
gprs mode gprs
gprs nsvc 0 remote ip ${GBPROXY_IP}
gprs nsvc 0 remote udp port ${GBPROXY_GB_PORT}
gprs nsvc 0 local udp port ${PCU_GB_PORT}
gprs nsvc 0 nsvci 1802
gprs nsei 1802
gprs cell bvci 1802
trx 0
rf_locked 0
arfcn 870
nominal power 23
max_power_red 20
timeslot 0
phys_chan_config CCCH+SDCCH4
timeslot 1
phys_chan_config SDCCH8
timeslot 2
phys_chan_config TCH/F
timeslot 3
phys_chan_config TCH/F
timeslot 4
phys_chan_config TCH/F
timeslot 5
phys_chan_config PDCH
timeslot 6
phys_chan_config PDCH
timeslot 7
phys_chan_config PDCH
e1_input
e1_line 0 driver ipa
msc 0
mgw remote-ip ${MGW4BSC_IP}
mgw remote-port ${MGW4BSC_PORT}
mgw endpoint-range 33 64
allow-emergency deny
codec-list fr1 hr1
${include(../common_logging)}
log stderr
logging level meas debug

View File

@ -0,0 +1,21 @@
gbproxy
sgsn nsei 101
ns
nse 101 nsvci 101
nse 101 remote-role sgsn
nse 101 encapsulation udp
nse 101 remote-ip ${SGSN_IP}
nse 101 remote-port ${SGSN_GB_PORT}
timer tns-block 3
timer tns-block-retries 3
timer tns-reset 3
timer tns-reset-retries 3
timer tns-test 30
timer tns-alive 3
timer tns-alive-retries 10
encapsulation framerelay-gre enabled 0
encapsulation framerelay-gre local-ip ${GBPROXY_IP}
encapsulation udp local-ip ${GBPROXY_IP}
encapsulation udp local-port ${GBPROXY_GB_PORT}
${include(../common_logging)}

View File

@ -0,0 +1,17 @@
log stderr
logging level all debug
logging filter all 1
logging print category 1
ggsn ggsn0
gtp bind-ip ${GGSN_IP}
apn internet
tun-device ${APN_DEV}
type-support v4
ip dns 0 ${GGSN_DNS0}
ip dns 1 ${GGSN_DNS1}
#ip ifconfig ${GGSN_NET}
ip prefix dynamic ${GGSN_NET}
no shutdown
default-apn internet
no shutdown ggsn
${include(../common_logging)}

View File

@ -0,0 +1,4 @@
hlr
ussd route prefix *1# internal own-msisdn
ussd route prefix *2# internal own-imsi
${include(../common_logging)}

View File

@ -0,0 +1,5 @@
hnbgw
iuh
local-ip ${HNBGW_IP}
${include(../common_logging)}

View File

@ -0,0 +1,11 @@
mgcp
bind ip ${MGW4BSC_IP}
# default port is 2427 (is used for MSC's MGW)
bind port ${MGW4BSC_PORT}
number endpoints 64
line vty
# default VTY interface is on 127.0.0.1 (used for MSC's MGW)
bind ${MGW4BSC_VTY_IP}
${include(../common_logging)}
logging level all info

View File

@ -0,0 +1,8 @@
mgcp
bind ip ${MGW4MSC_IP}
number endpoints 64
line vty
bind ${MGW4MSC_VTY_IP}
${include(../common_logging)}
logging level all info

15
net/tmpl_std/osmo-msc.cfg Normal file
View File

@ -0,0 +1,15 @@
network
network country code ${MCC}
mobile network code ${MNC}
authentication required
encryption a5 0
msc
mgw remote-ip ${MGW4MSC_IP}
mgw endpoint-range 1 32
${include(../common_logging)}
logging level ref debug
logging level vlr debug
log stderr
logging level ref debug
logging level vlr debug

View File

@ -0,0 +1,12 @@
sgsn
gtp local-ip ${SGSN_IP}
ggsn 0 remote-ip ${GGSN_IP}
ggsn 0 gtp-version 1
auth-policy remote
gsup remote-ip ${HLR_IP}
ns
encapsulation udp local-ip ${SGSN_IP}
encapsulation udp local-port ${SGSN_GB_PORT}
encapsulation framerelay-gre enabled 0
${include(../common_logging)}

View File

@ -0,0 +1,6 @@
cs7 instance 0
xua rkm routing-key-allocation dynamic-permitted
listen m3ua 2905
accept-asp-connections dynamic-permitted
${include(../common_logging)}

125
net/tmpl_std/run.sh Executable file
View File

@ -0,0 +1,125 @@
#!/usr/bin/env bash
../stale_config.sh
dev="${ETH_DEV}"
ip2="${PUBLIC_IP2}"
apn="${APN_DEV}"
sudo true || exit 1
if [ -z "$(sudo iptables -L -t nat | grep MASQUERADE)" ]; then
sudo iptables -t nat -A POSTROUTING -s ${GGSN_NET} -o $dev -j MASQUERADE
fi
if [ "$(sudo cat /proc/sys/net/ipv4/ip_forward)" = "0" ]; then
sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
fi
if [ -z "$(ip tuntap show | grep $apn)" ]; then
sudo ip tuntap add dev $apn mode tun user $USER group $USER
sudo ip addr add ${GGSN_NET} dev $apn
sudo ip link set $apn up
fi
if [ -z "$(ip addr show dev $dev | grep "$ip2")" ]; then
sudo ip addr add ${PUBLIC_IP2}/32 dev $dev
fi
logdir="current_log"
mkdir -p "$logdir"
term() {
title="$2"
if [ -z "$title" ]; then
title="$(basename $@)"
fi
terminal="$(which urxvt || which xterm)"
if ! which $terminal; then
echo "CANNOT FIND XTERM PROGRAM"
fi
exec $terminal -title "CN:$title" -e sh -c "export LD_LIBRARY_PATH='/usr/local/lib'; $1; echo; while true; do echo 'q Enter to close'; read q_to_close; if [ \"x\$q_to_close\" = xq ]; then break; fi; done"
}
sudo tcpdump -i $dev -n -w current_log/$dev.single.pcap -U not port 22 &
sudo tcpdump -i lo -n -w current_log/lo.single.pcap -U not port 22 &
hnbgw="osmo-hnbgw"
msc="gdb -ex run --args $(which osmo-msc)"
gbproxy="osmo-gbproxy"
sgsn="osmo-sgsn"
ggsn="osmo-ggsn"
mgw4msc="osmo-mgw -c osmo-mgw-for-msc.cfg"
#mgw4bsc="gdb -ex run --args osmo-mgw -c osmo-mgw-for-bsc.cfg"
#mgw4bsc="strace osmo-mgw -c osmo-mgw-for-bsc.cfg"
mgw4bsc="osmo-mgw -c osmo-mgw-for-bsc.cfg"
hlr="LD_LIBRARY_PATH=/usr/local/lib gdb -ex run --args osmo-hlr"
stp="osmo-stp"
bsc="LD_LIBRARY_PATH=/usr/local/lib gdb -ex run --args osmo-bsc -c osmo-bsc.cfg"
term "$ggsn" GGSN &
sleep .2
term "$stp" STP &
sleep .2
term "$hlr" HLR &
sleep .2
term "$sgsn" SGSN &
sleep .2
term "$gbproxy" GBPROXY &
sleep .2
term "$mgw4msc" MGW4MSC &
sleep .2
term "$mgw4bsc" MGW4BSC &
sleep .2
term "$msc" MSC &
sleep 2
term "$hnbgw" HNBGW &
sleep .2
term "$bsc" BSC &
#ssh bts rm /tmp/bts.log /tmp/pcu.log
#ssh bts neels/run_remote.sh &
echo enter to close
read enter_to_close
echo Closing...
#ssh bts neels/stop_remote.sh
kill %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12
killall osmo-msc
killall osmo-bsc
killall osmo-gbproxy
killall osmo-sgsn
#killall osmo-hnbgw
killall osmo-mgw
killall osmo-hlr
killall -9 osmo-stp
sudo killall tcpdump
killall osmo-ggsn
set +e
cp *.cfg "$logdir"/
echo
echo enter name to save log
read log_name
if [ -n "$log_name" ]; then
newlogdir="log/$log_name"
#scp "bts:/tmp/{bts,pcu}.log" "bts:neels/osmo-{bts,pcu}.cfg" "$logdir"
else
newlogdir="autolog/log_$(date +%Y-%m-%d_%H-%M-%S)"
fi
mkdir -p "$(dirname "$newlogdir")"
mergecap -w "$logdir/trace.pcap" "$logdir/"*.single.pcap && rm -f "$logdir/"*.single.pcap
if [ -x "$newlogdir" ]; then
echo "already exists, move it manually: $newlogdir"
else
echo mv "$logdir" "$newlogdir"
mv "$logdir" "$newlogdir"
mkdir -p "$logdir"
logdir="$newlogdir"
fi
rm lastlog
ln -s "$logdir" lastlog