gbproxy: remove (moved to own repository)

New repository:
https://git.osmocom.org/osmo-gbproxy/

Related: OS#4992
Change-Id: I37f7cebaf2a06bd93627a452f5df44edcfc0f87a
This commit is contained in:
Oliver Smith 2021-02-01 12:48:48 +01:00 committed by osmith
parent 4be5ab3707
commit 901ed14c89
42 changed files with 5 additions and 6710 deletions

1
.gitignore vendored
View File

@ -41,7 +41,6 @@ ltmain.sh
# apps and app data
src/sgsn/osmo-sgsn
src/gbproxy/osmo-gbproxy
src/gtphub/osmo-gtphub
src/libcommon/gsup_test_client

View File

@ -259,7 +259,6 @@ AC_OUTPUT(
src/Makefile
src/gprs/Makefile
src/sgsn/Makefile
src/gbproxy/Makefile
src/gtphub/Makefile
tests/Makefile
tests/atlocal

View File

@ -1,58 +0,0 @@
#!/usr/bin/env python
"""
demonstrate a unblock bug on the GB Proxy..
"""
bts_ns_reset = "\x02\x00\x81\x01\x01\x82\x1f\xe7\x04\x82\x1f\xe7"
ns_reset_ack = "\x03\x01\x82\x1f\xe7\x04\x82\x1f\xe7"
bts_ns_unblock = "\x06"
ns_unblock_ack = "\x07"
bts_bvc_reset_0 = "\x00\x00\x00\x00\x22\x04\x82\x00\x00\x07\x81\x03\x3b\x81\x02"
ns_bvc_reset_0_ack = "\x00\x00\x00\x00\x23\x04\x82\x00\x00"
bts_bvc_reset_8167 = "\x00\x00\x00\x00\x22\x04\x82\x1f\xe7\x07\x81\x08\x08\x88\x72\xf4\x80\x10\x1c\x00\x9c\x40"
import socket
socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
socket.bind(("0.0.0.0", 0))
socket.setblocking(1)
import sys
port = int(sys.argv[1])
print "Sending data to port: %d" % port
def send_and_receive(packet):
socket.sendto(packet, ("127.0.0.1", port))
try:
data, addr = socket.recvfrom(4096)
except socket.error, e:
print "ERROR", e
import sys
sys.exit(0)
return data
#send stuff once
to_send = [
(bts_ns_reset, ns_reset_ack, "reset ack"),
(bts_ns_unblock, ns_unblock_ack, "unblock ack"),
(bts_bvc_reset_0, ns_bvc_reset_0_ack, "BVCI=0 reset ack"),
]
for (out, inp, type) in to_send:
res = send_and_receive(out)
if res != inp:
print "Failed to get the %s" % type
sys.exit(-1)
import time
time.sleep(3)
res = send_and_receive(bts_bvc_reset_8167)
print "Sent all messages... check wireshark for the last response"

View File

@ -61,14 +61,6 @@ Group: Productivity/Telephony/Servers
%description -n osmo-gtphub
Osmocom GTP Hub: Proxy for GTP traffic between multiple SGSNs and GGSNs.
%package -n osmo-gbproxy
Summary: Osmocom GPRS Gb Interface Proxy
Group: Productivity/Telephony/Servers
%description -n osmo-gbproxy
The purpose of the Gb proxy is to aggregate the Gb links of multiple
BSS's and present them in one Gb link to the SGSN.
%prep
%setup -q
@ -95,10 +87,6 @@ make %{?_smp_mflags}
%postun -n osmo-gtphub %service_del_postun osmo-gtphub.service
%pre -n osmo-gtphub %service_add_pre osmo-gtphub.service
%post -n osmo-gtphub %service_add_post osmo-gtphub.service
%preun -n osmo-gbproxy %service_del_preun osmo-gbproxy.service
%postun -n osmo-gbproxy %service_del_postun osmo-gbproxy.service
%pre -n osmo-gbproxy %service_add_pre osmo-gbproxy.service
%post -n osmo-gbproxy %service_add_post osmo-gbproxy.service
%endif
%check
@ -109,7 +97,6 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%dir %{_docdir}/%{name}/examples
%dir %{_docdir}/%{name}/examples/osmo-sgsn
%exclude %{_docdir}/%{name}/examples/osmo-gtphub
%exclude %{_docdir}/%{name}/examples/osmo-gbproxy
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn.cfg
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg
@ -128,13 +115,4 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%config(noreplace) %{_sysconfdir}/osmocom/osmo-gtphub.cfg
%{_unitdir}/osmo-gtphub.service
%files -n osmo-gbproxy
%dir %{_docdir}/%{name}/examples
%dir %{_docdir}/%{name}/examples/osmo-gbproxy
%{_docdir}/%{name}/examples/osmo-gbproxy/osmo-gbproxy.cfg
%{_bindir}/osmo-gbproxy
%dir %{_sysconfdir}/osmocom
%config(noreplace) %{_sysconfdir}/osmocom/osmo-gbproxy.cfg
%{_unitdir}/osmo-gbproxy.service
%changelog

View File

@ -1,11 +1,9 @@
EXTRA_DIST = \
osmo-gbproxy.service \
osmo-gtphub.service \
osmo-sgsn.service
if HAVE_SYSTEMD
SYSTEMD_SERVICES = \
osmo-gbproxy.service \
osmo-gtphub.service \
osmo-sgsn.service

View File

@ -1,12 +0,0 @@
[Unit]
Description=Osmocom Gb proxy
[Service]
Type=simple
ExecStart=/usr/bin/osmo-gbproxy -c /etc/osmocom/osmo-gbproxy.cfg
Restart=always
RestartSec=2
RestartPreventExitStatus=1
[Install]
WantedBy=multi-user.target

16
debian/control vendored
View File

@ -53,22 +53,6 @@ Priority: extra
Depends: osmo-gtphub (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for Osmocom GTP Hub
Package: osmo-gbproxy
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends}
Recommends: osmo-sgsn
Description: Osmocom GPRS Gb Interface Proxy
The purpose of the Gb proxy is to aggregate the Gb links of multiple
BSS's and present them in one Gb link to the SGSN.
Package: osmo-gbproxy-dbg
Architecture: any
Section: debug
Priority: extra
Depends: osmo-gbproxy (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for Osmocom GPRS Gb Interface Proxy
Package: osmo-sgsn-doc
Architecture: all
Section: doc

9
debian/copyright vendored
View File

@ -19,12 +19,10 @@ Files: .gitignore
contrib/ipa.py
contrib/jenkins.sh
contrib/soap.py
contrib/systemd/osmo-gbproxy.service
contrib/systemd/osmo-sgsn.service
contrib/twisted_ipa.py
doc/Makefile.am
doc/examples/Makefile.am
doc/examples/osmo-gbproxy/osmo-gbproxy.cfg
doc/examples/osmo-gtphub/gtphub-example.txt
doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg
doc/examples/osmo-gtphub/osmo-gtphub.cfg
@ -50,8 +48,6 @@ Files: .gitignore
src/gprs/osmo_sgsn.cfg
tests/Makefile.am
tests/atlocal.in
tests/gbproxy/Makefile.am
tests/gbproxy/gbproxy_test.ok
tests/gprs/Makefile.am
tests/gprs/gprs_test.c
tests/gprs/gprs_test.ok
@ -85,10 +81,6 @@ Files: include/osmocom/sgsn/a_reset.h
src/gprs/gprs_gb_parse.c
src/gprs/gprs_utils.c
src/gprs/sgsn_ares.c
src/gbproxy/gb_proxy.c
src/gbproxy/gb_proxy_main.c
src/gbproxy/gb_proxy_peer.c
src/gbproxy/gb_proxy_vty.c
src/gtphub/gtphub.c
src/gtphub/gtphub_main.c
src/gtphub/gtphub_vty.c
@ -139,7 +131,6 @@ License: AGPL-3.0+
Files: src/gtphub/gtphub_ares.c
src/gtphub/gtphub_sock.c
tests/gbproxy/gbproxy_test.c
Copyright: 2013 Jacob Erlbeck <jerlbeck@sysmocom.de>
2013 sysmocom s.f.m.c. GmbH
2014 Holger Hans Peter Freyther

View File

@ -1,151 +0,0 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: osmo-gbproxy
# Required-Start: $network $local_fs
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Osmocom GBproxy
# Description: A tool to proxy the GPRS Gb interface.
### END INIT INFO
# Author: Harald Welte <laforge@gnumonks.org>
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
NAME=osmo-gbproxy # Introduce the short server's name here
DESC="Osmocom GBProxy" # Introduce a short description here
DAEMON=/usr/bin/osmo-gbproxy # Introduce the server's location here
SCRIPTNAME=/etc/init.d/osmocom-gbproxy
CONFIG_FILE=/etc/osmocom/osmocom-gbproxy.cfg
# Exit if the package is not installed
[ -x $DAEMON ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/osmocom-gbproxy ] && . /etc/default/osmocom-gbproxy
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
DAEMON_ARGS="-D -c $CONFIG_FILE"
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
return "$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet $PIDFILE --name $NAME
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac
:

View File

@ -1,4 +0,0 @@
etc/osmocom/osmo-gbproxy.cfg
lib/systemd/system/osmo-gbproxy.service
usr/bin/osmo-gbproxy
usr/share/doc/osmo-sgsn/examples/osmo-gbproxy/osmo-gbproxy.cfg usr/share/doc/osmo-gbproxy/examples

1
debian/rules vendored
View File

@ -58,7 +58,6 @@ override_dh_auto_configure:
override_dh_strip:
dh_strip -posmo-sgsn --dbg-package=osmo-sgsn-dbg
dh_strip -posmo-gtphub --dbg-package=osmo-gtphub-dbg
dh_strip -posmo-gbproxy --dbg-package=osmo-gbproxy-dbg
# Print test results in case of a failure
override_dh_auto_test:

View File

@ -1,7 +1,7 @@
OSMOCONF_FILES = \
osmo-gtphub/osmo-gtphub.cfg \
osmo-sgsn/osmo-sgsn.cfg \
osmo-gbproxy/osmo-gbproxy.cfg
$(NULL)
osmoconfdir = $(sysconfdir)/osmocom
osmoconf_DATA = $(OSMOCONF_FILES)

View File

@ -1,42 +0,0 @@
!
! OsmoGbProxy (UNKNOWN) configuration saved from vty
!!
!
log stderr
logging filter all 1
logging color 1
logging timestamp 0
logging level all debug
logging level gprs debug
logging level ns info
logging level bssgp debug
logging level lglobal notice
logging level llapd notice
logging level linp notice
logging level lmux notice
logging level lmi notice
logging level lmib notice
logging level lsms notice
!
line vty
no login
!
ns
bind udp local
listen 127.0.0.1 23000
accept-ipaccess
nse 666
nsvc ipa local 127.0.0.1 23001 nsvci 666
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
gbproxy
sgsn nsei 666
core-mobile-country-code 666
core-mobile-network-code 6
core-access-point-name none match-imsi ^666066|^66607
tlli-list max-length 200

View File

@ -1,32 +0,0 @@
!
! Osmocom Gb Proxy (0.9.0.404-6463) configuration saved from vty
!!
!
line vty
no login
!
gbproxy
nri bitlen 4
nri null add 0 4
sgsn nsei 101
name main
nri add 1
nri add 11
sgsn nsei 102
nri add 2
nri add 12
ns
bind udp local
listen 127.0.0.100 23000
accept-ipaccess
nse 101
nsvc ipa local 192.168.100.239 7777 nsvci 101
nse 102
nsvc ipa local 192.168.100.239 7778 nsvci 102
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

View File

@ -1,23 +0,0 @@
!
! Osmocom Gb Proxy (0.9.0.404-6463) configuration saved from vty
!!
!
line vty
no login
!
gbproxy
sgsn nsei 101
name main
ns
bind udp local
listen 127.0.0.100 23000
accept-ipaccess
nse 101
nsvc ipa local 192.168.100.239 7777 nsvci 101
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

View File

@ -1,21 +1,17 @@
EXTRA_DIST = osmosgsn-usermanual.adoc \
osmosgsn-usermanual-docinfo.xml \
osmosgsn-vty-reference.xml \
osmogbproxy-usermanual.adoc \
osmogbproxy-usermanual-docinfo.xml \
regen_doc.sh \
chapters \
vty \
osmogbproxy-vty-reference.xml \
vty-osmogbproxy \
$(NULL)
if BUILD_MANUALS
ASCIIDOC = osmosgsn-usermanual.adoc osmogbproxy-usermanual.adoc
ASCIIDOC = osmosgsn-usermanual.adoc
ASCIIDOC_DEPS = $(srcdir)/chapters/*.adoc
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
VTY_REFERENCE = osmosgsn-vty-reference.xml osmogbproxy-vty-reference.xml
VTY_REFERENCE = osmosgsn-vty-reference.xml
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
OSMO_REPOSITORY = osmo-sgsn

View File

@ -1,41 +0,0 @@
== Configuring OsmoGbProxy
OsmoGbProxy requires very little configuration, most of it being the
configuration of the NS links.
Most config options specific to OsmoGbProxy are related to SGSN pooling and
telling the proxy which NSE(s) it should use to talk to the SGSN(s).
=== Configure the Network Service (NS)
A detailed description of the NS configuration can be found in <<libosmogb>>.
The following config snippets assume the SGSN(s) (NSEI 101 and 102) are using
IP-SNS and listen on 10.0.1.1:23000 and 10.0.1.2:23000 respectively.
This would be the NS config for the SGSN(s):
.Example: NS configuration example (SGSN)
----
ns
bind udp local
listen 10.0.0.1 23000 <1>
nse 101 <2>
ip-sns 10.0.1.1 23000 <3>
nse 102
ip-sns 10.0.1.2 23000
----
<1> Define the local IP/port from which to connect
<2> Define an NSE with NSEI
<3> Use IP-SNS to connect to the SGSN
=== Configure an SGSN
Configuration of a single (non-pooling) SGSN is rather simple.
.Example: SGSN configuration example
----
sgsn 101 <1>
name Main SGSN <2>
----
<1> Each SGSN is identified by its NSEI (same as in the NS configuration)
<2> An SGSN can optionally have a name. If none is set a default name will be used.

View File

@ -1,29 +0,0 @@
[[control]]
== Control interface
The actual protocol is described in <<common-control-if>>, the variables
common to all programs using it are described in <<ctrl_common_vars>>. Here we
describe variables specific to OsmoGbProxy.
.Variables available over control interface
[options="header",width="100%",cols="20%,5%,5%,50%,20%"]
|===
|Name|Access|Trap|Value|Comment
|nsvc-state|RO|No|"<nsei>,<nsvci>,<local-alive>,<local-blocked>,<remote-role>,<remote-alive>,<remote-blocked>"|See <<nsvc_state>> for details.
|gbproxy-state|RO|No|"<nsei>,<bvci>,<mcc>,<mnc>,<lac>,<rac>,<blocked>"|See <<gbproxy_state>> for details.
|number-of-peers|RO|No|"<num-of-bss>"|Count of concurrent BSS(BTS) peers.
|===
[[nsvc_state]]
=== nsvc-state
Return the list of active NS-VCs (NS Virtual Circuits), including information
on the key parameters, such as NSEI, NSVCI and the local + remote ALIVE
and BLOCKED state.
[[gbproxy_state]]
=== gbproxy-state
Return the list of active Peers, including information on the key
parameters, such as NSEI, BVCI, and the MCC-MNC-LAC-RAC of the attached
BSS, as well as the overall state (BLOCKED or UNBLOCKED).

View File

@ -1,113 +0,0 @@
[[chapter_details]]
== Proxy details
=== BVC handling
This section describes in more detail how BVCs are handled in OsmoGbProxy
If a BSS connects to OsmoGbProxy while the SGSN is not available it will
acknowledge the BVC RESET on the signalling BVC, but ignore other messages
(especially any PTP BVC RESET).
.BSS connects to OsmoGbProxy
[mscgen]
----
msc {
hscale="1.8";
bss1 [label="BSS1"], bss2 [label="BSS2"], gbproxy [label="GbProxy"], sgsn [label="SGSN"];
bss1 <=> gbproxy [label="NS link available"];
bss1 => gbproxy [label="BVC RESET (BVCI=0)"];
gbproxy => bss1 [label="BVC RESET ACK"];
bss1 -x gbproxy [label="PTP BVC RESET (ignored)"];
}
----
As soon as the SGSN is reachable through NS OsmoGbProxy will send a BVC RESET
to the signalling BVC towards the SGSN. After that completes it will reset the
signalling BVC of all BSS connections. At this point the BSS will send a BVC
RESET for its PTP BVCs which will be forwarded to the SGSN, similarly the PTP
BVC RESET ACK from the SGSN will be sent back to the BSS.
.SGSN connection to OsmoGbProxy
[mscgen]
----
msc {
hscale="1.8";
bss1 [label="BSS1"], bss2 [label="BSS2"], gbproxy [label="GbProxy"], sgsn [label="SGSN"];
gbproxy <=> sgsn [label="NS link available"];
gbproxy => sgsn [label="BVC RESET (BVCI=0)"];
sgsn => gbproxy [label="BVC RESET ACK"];
gbproxy => bss1 [label="BVC RESET (BVCI=0)"];
bss1 => gbproxy [label="BVC RESET ACK"];
bss1 box bss1 [label="PTP BVCs need to be reset"];
bss1 => gbproxy [label="PTP BVC RESET (BVCI=x)"];
gbproxy => sgsn [label="PTP BVC RESET (BVCI=x)"];
sgsn => gbproxy [label="PTP BVC RESET ACK (BVCI=x)"];
gbproxy => bss1 [label="PTP BVC RESET ACK (BVCI=x)"];
bss2 <=> sgsn [label="BVCI x established"];
}
----
The communication on the PTP BVC will then be forwarded between the BSS and the
SGSN.
If a BSS connects while the SGSN is up the PTP BVC RESET will directly be
forwarded.
.BSS connects to OsmoGbProxy
[mscgen]
----
msc {
hscale="1.8";
bss1 [label="BSS1"], bss2 [label="BSS2"], gbproxy [label="GbProxy"], sgsn [label="SGSN"];
bss2 <=> gbproxy [label="NS link available"];
bss2 => gbproxy [label="BVC RESET (BVCI=0)"];
gbproxy => bss2 [label="BVC RESET ACK"];
bss2 => gbproxy [label="PTP BVC RESET (BVCI=y)"];
gbproxy => sgsn [label="PTP BVC RESET (BVCI=y)"];
sgsn => gbproxy [label="PTP BVC RESET ACK (BVCI=y)"];
gbproxy => bss2 [label="PTP BVC RESET ACK (BVCI=y)"];
bss2 <=> sgsn [label="BVCI y established"];
}
----
If OsmoGbProxy looses the connection to the SGSN it will reset the signalling
BVC of all BSS connections. This ensures that the BSS will not send traffic
over a PTP BVC before its reset procedure has been completed.
.SGSN connection fails
[mscgen]
----
msc {
hscale="1.8";
bss1 [label="BSS1"], bss2 [label="BSS2"], gbproxy [label="GbProxy"], sgsn [label="SGSN"];
gbproxy <=> sgsn [label="NS link fails"];
gbproxy => bss1 [label="BVC RESET (BVCI=0)"];
gbproxy => bss2 [label="BVC RESET (BVCI=0)"];
}
----
When the connection to the SGSN is eventually restored the signalling BVC
between OsmoGbProxy and SGSN will be reset.
After that completes OsmoGbProxy will reset the signalling BVC on all BSS NS
connections and forward the PTP BVC RESET messages.
.SGSN connection restored
[mscgen]
----
msc {
hscale="1.8";
bss1 [label="BSS1"], bss2 [label="BSS2"], gbproxy [label="GbProxy"], sgsn [label="SGSN"];
gbproxy <=> sgsn [label="NS link available"];
gbproxy => sgsn [label="BVC RESET (BVCI=0)"];
sgsn => gbproxy [label="BVC RESET ACK"];
gbproxy => bss1 [label="BVC RESET (BVCI=0)"];
bss1 => gbproxy [label="BVC RESET ACK"];
bss1 box bss1 [label="PTP BVCs need to be reset"];
gbproxy => bss2 [label="BVC RESET (BVCI=0)"];
bss2 => gbproxy [label="BVC RESET ACK"];
bss2 box bss2 [label="PTP BVCs need to be reset"];
}
----

View File

@ -1,95 +0,0 @@
[[chapter_overview]]
== Overview
IMPORTANT: If you have used an earlier version of OsmoGbProxy please note
that support for various features such as PLMN/APN patching, support for a
secondary SGSN has been removed.
=== About OsmoGbProxy
OsmoGbProxy is the Osmocom proxy for the 3GPP Gb interface. The Gb
interface is defined by 3GPP as the protocol between the BSS and the
SGSN inside the 2G/2.5G/2.75G packet switched network domain.
As Osmocom implements a BTS-colocated PCU, there are potentially many
Gb interface connections between all those many PCUs in the network
and the SGSN. This can be cumbersome to configure/maintain at the
SGSN side.
OsmoGbProxy aggregates many PCU-facing Gb connections into one Gb
connection to the SGSN. This is achieved by
* maintaining separate NS-VCs on the PCU side and on the SGSN side
* more or less transparently routing BSSGP peer-to-peer Virtual Circuits
(BVCs) through the proxy
* having some special handling for the signaling BVC (BVCI=0) which is
shared among all the PCUs connected to the proxy
=== Data Model
==== gbproxy_config
This contains the parsed configuration of the OsmoGbProxy.
==== gbproxy_nse
The remote NS-entity that the proxy interacts with. Includes
information about:
* the [unique] NSEI of the peer
* the Routeing Area (RA) of the peer
* which side this NSE is facing - SGSN or BSS
* the list of BVCs in this NSE
==== gbproxy_bvc
A ptp-BVC on an NSE
* the BVCI of this BVC
* the routing area of this BVC
* the BVC state machine
==== gbproxy_cell
This contains a view of the cell and its associated BVCs
* the unique BVCI of this cell
* the routing area of this cell
* one bss-side BVC
* one BVC per SGSN in the pool
==== gbproxy_sgsn
Represents one SGSN in the pool. Contains:
* the NSE belonging to this SGSN
* a (configurable) name of the SGSN
* pool-related configuration of the SGSNs
==== IMSI cache
In order to route messages to the correct BSS or SGSN OsmoGbProxy
sometimes needs to cache where messages came from.
In BSS->SGSN direction the IMSI-cache is needed for
* paging ps reject
* dummy paging response
when SGSN-pooling is enabled and multiple SGSNs are configured. The IMSI
contained in a paging ps or dummy paging message is cached together with
the originating SGSN/NSE. The answer, which also contains the IMSI, is
then routed back to the original SGSN.
==== TLLI cache
In SGSN->BSS direction OsmoGbProxy needs a TLLI cache to correctly route the
following messages:
* suspend ack/nack
* resume ack/nack
Suspend/resume are sent over the signalling BVC to the SGSN. OsmoGbProxy saves
the TLLI->NSE association in the TLLI cache and routes the ack/nack back to
the signalling BVC of the originating NSE.

View File

@ -1,39 +0,0 @@
== Running OsmoGbProxy
The OsmoGbProxy executable (`osmo-gbproxy`) offers the following command-line
options:
=== SYNOPSIS
*osmo-gbproxy* [-h|-V] [-d 'DBGMASK'] [-D] [-c 'CONFIGFILE'] [-s] [-e 'LOGLEVEL'] [-T]
=== OPTIONS
*-h, --help*::
Print a short help message about the supported options
*-V, --version*::
Print the compile-time version number of the program
*-d, --debug 'DBGMASK','DBGLEVELS'*::
Set the log subsystems and levels for logging to stderr. This
has mostly been superseded by VTY-based logging configuration,
see <<logging>> for further information.
*-D, --daemonize*::
Fork the process as a daemon into background.
*-c, --config-file 'CONFIGFILE'*::
Specify the file and path name of the configuration file to be
used. If none is specified, use `osmo_sgsn.cfg` in the current
working directory.
*-s, --disable-color*::
Disable colors for logging to stderr. This has mostly been
deprecated by VTY based logging configuration, see <<logging>>
for more information.
*-e, --log-level 'LOGLEVEL'*::
Set the global log level for logging to stderr. This has mostly
been deprecated by VTY based logging configuration, see
<<logging>> for more information.
*-T, --timestamp*::
Enable prefixing each log line on stderr with a timestamp. This
has mostly been deprecated by VTY based logging configuration, see
<<logging>> for more information.

View File

@ -1,219 +0,0 @@
== SGSN Pooling
SGSN pooling is described in 3GPP TS 23.236 <<3gpp-ts-23-236>>, and is supported
by OsmoGbProxy since early 2021.
The aim of SGSN pooling is to distribute load from a BSS across multiple SGSNs,
which are equivalent and redundant infrastructure for the same core network.
The main mechanism for SGSN pooling is the TLLI/P-TMSI, which an SGSN hands out
to its attached subscribers. Typically 10 bits of the P-TMSI are designated as a
Network Resource Identifier (NRI) that identifies the originating SGSN, and
allows OsmoGbProxy to direct a subscriber back to the same SGSN instance that
previously negotiated the Attach procedure. Typically, the full NRI value
range available is divided into N even ranges, where each SGSN is assigned one
NRI range.
Subscribers attaching without a TLLI, or those with unknown NRI value,
are evenly distributed across SGSN instances. OsmoGbProxy uses a hash-based
approach to distribute load across all connected SGSNs.
A Paging Response from a subscriber is always returned back to whichever SGSN
initiated the Paging, regardless of the Mobile Identity used.
Finally, a NULL-NRI is a special NRI value that indicates that the SGSN wishes
to offload this subscriber to a different SGSN. A NULL-NRI is an arbitrary NRI
value that is chosen distinctly for each PLMN served by a BSS, so that a
subscriber can be reassigned within that PLMN. Upon (periodic) Location
Updating, an offloading SGSN hands out a NULL-NRI value in the assigned TLLI,
along with a non-broadcast LAI. The subscriber will notice the LAI mismatch,
and immediately re-attempt the attach using the TLLI containing the NULL-NRI.
OsmoGbProxy recognises the NULL-NRI and redirects the subscriber to one of the
other SGSNs. A prerequisite for this to work well is that the particular SGSN is
previously marked as not accepting new subscribers, in OsmoGbProxy's configuration.
The mechanisms described above make up the NAS node selection function
implemented in OsmoGbProxy.
3GPP TS 23.236 also defines that an offloading SGSN hands subscriber information
to the newly assigned SGSN, which takes place outside the scope of OsmoGbProxy.
=== Configuring SGSN Pooling
The NRI ranges assigned to each SGSN must match in the OsmoGbProxy and the SGSN
configuration. If inconsistent NRI value ranges are configured,
attached subscribers would be redirected to SGSN instances that did not perform the
attach, possibly rendering the core network unusable.
==== Connecting Multiple SGSNs
----
# Configure the Network Service
ns
bind udp sgsn
listen 10.0.0.1 23000
nse 1
ip-sns 10.0.1.1 23000
ip-sns 10.0.1.1 23001
nse 2
ip-sns 10.0.1.2 23000
nse 3
ip-sns 10.0.1.3 23000
# configure NRI value ranges
gbproxy
nri bitlen 10
nri null add 0
sgsn 1
nri add 1 341
sgsn 2
nri add 342 682
sgsn 3
nri add 683 1023
----
==== NRI Value Bit Length
In OsmGbProxy, the NRI value's bit length is freely configurable from 0 to 15
bits. 3GPP TS 23.236 suggests a typical bit length of 10. Setting the length
to 0 disables SGSN pooling, this is also the default.
The NRI bit length must be identical across the entire SGSN pool.
Change the NRI value bit length in OsmoGbProxy's VTY configuration like this:
----
gbproxy
nri bitlen 10
----
In the TMSI bits, regardless of the NRI bit length, the NRI value always starts
just after the most significant octet of a TMSI (most significant bit at TMSI's
bit 23).
==== NULL-NRI
Since OsmoGbProxy supports serving only one PLMN, NULL-NRI are configured globally.
Even though 3GPP TS 23.236 indicates that there is a single NULL-NRI per PLMN,
OsmoGbProxy allows configuring multiple NULL-NRI values.
----
network
nri null add 0
nri null add 423
----
==== Assigning NRI Ranges to SGSNs
Each SGSN configured in OsmoGbProxy must be assigned a distinct NRI value range.
Overlapping NRI value ranges will cause failure to serve subscribers.
NRI values are typically configured in ranges, here dividing a 10bit range
(0..1023) into three equal ranges, while leaving 0 available to be configured
as NULL-NRI:
----
sgsn nsei 1
nri add 1 341
sgsn nsei 2
nri add 342 684
sgsn nsei 3
nri add 685 1023
----
NRI can also be assigned in single values:
----
sgsn nsei 1
nri add 23
----
Ranges can be constructed arbitrarily by a sequence of `add` and `del`
configurations, here a contrived example:
----
sgsn nsei 1
nri add 0 342
nri del 23
nri del 42 235
nri add 1000 1023
----
On the VIEW and ENABLE VTY nodes, `show nri all` shows all SGSNs:
----
OsmoGbProxy> show nri all
sgsn nsei 1
nri add 1 341
sgsn nsei 2
nri add 342 684
sgsn nsei 3
nri add 685 1023
----
When configuring overlapping NRI value ranges across SGSNs, the telnet VTY warns
about it, and starting OsmoGbProxy with such a configuration will fail:
----
sgsn nsei 1
nri add 1 511
sgsn nsei 2
nri add 512 1023
sgsn nsei 3
nri add 500 555
----
This results in:
----
$ osmo-gbproxy
% Warning: NSE(00003/SGSN): NRI range [500..555] overlaps between NSE 00003 and NSE 00001. For overlaps, NSE 00001 has higher priority than NSE 00003
% Warning: NSE(00003/SGSN): NRI range [500..555] overlaps between NSE 00003 and NSE 00002. For overlaps, NSE 00002 has higher priority than NSE 00003
----
==== SGSN Offloading
To effectively offload a particular SGSN, it must be marked as no longer taking
new subscribers in OsmoGbProxy. This can be achieved in the telnet VTY by:
----
sgsn nsei 1
no allow-attach
----
This SGSN will, as long as it is connected, continue to serve subscribers
already attached to it: those that yield an NRI matching this SGSN, and those
that are being paged by this SGSN. But OsmoGbProxy will no longer direct new
subscribers to this SGSN.
TODO: Is paging response relevant for SGSN?
To re-enable an SGSN for attaching new subscribers:
----
sgsn nsei 1
allow-attach
----
==== Traffic allocation
In a SGSN pool, osmo-gbproxy is facing the problem of dividing the downlink
capacity of a cell towards the SGSN. The BSS advertises the per-BVC capacity
by means of the BSSGP FLOW-CONTROL-BVC messages, but as there are multiple
SGSN in a pool, they all have to share / divide that total capacity.
By default, osmo-gbproxy advertises the full capacity to _each_ of the SGSN
pool members, which results in significant over-provisioning and can lead to
overload situations.
The administrator can configure the _percentage_ of the overall BSS-advertised
capacity that shall be reported to each pool member SGSN using the
`pool bvc-flow-control-ratio <1-100>` configuration command.
A setting of 100 means that each pool member is informed of 100% of the
BSS side capacity.
A setting of 25 means that each pool member is informed of 25% of the
BSS side capacity. This would make most sense in a set-up with four
SGSN of equal share.
More complex capacity division schemes are so far not supported by
osmo-gbproxy.

View File

@ -1,46 +0,0 @@
<revhistory>
<revision>
<revnumber>1</revnumber>
<date>March 21, 2019</date>
<authorinitials>HW</authorinitials>
<revremark>
Initial version.
</revremark>
</revision>
</revhistory>
<authorgroup>
<author>
<firstname>Harald</firstname>
<surname>Welte</surname>
<email>hwelte@sysmocom.de</email>
<authorinitials>HW</authorinitials>
<affiliation>
<shortaffil>sysmocom</shortaffil>
<orgname>sysmocom - s.f.m.c. GmbH</orgname>
<jobtitle>Managing Director</jobtitle>
</affiliation>
</author>
</authorgroup>
<copyright>
<year>2013-2019</year>
<holder>sysmocom - s.f.m.c. GmbH</holder>
</copyright>
<legalnotice>
<para>
Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License,
Version 1.3 or any later version published by the Free Software
Foundation; with no Invariant Sections, no Front-Cover Texts,
and no Back-Cover Texts. A copy of the license is included in
the section entitled "GNU Free Documentation License".
</para>
<para>
The Asciidoc source code of this manual can be found at
<ulink url="https://git.osmocom.org/osmo-sgsn/doc/">
https://git.osmocom.org/osmo-sgsn/doc/
</ulink>
</para>
</legalnotice>

View File

@ -1,36 +0,0 @@
:gfdl-enabled:
OsmoGbProxy User Manual
=======================
Harald Welte <hwelte@sysmocom.de>
include::./common/chapters/preface.adoc[]
include::{srcdir}/chapters/gbproxy-overview.adoc[]
include::{srcdir}/chapters/gbproxy-details.adoc[]
include::{srcdir}/chapters/gbproxy-running.adoc[]
include::{srcdir}/chapters/gbproxy-control.adoc[]
include::./common/chapters/vty.adoc[]
include::./common/chapters/logging.adoc[]
include::{srcdir}/chapters/gbproxy-configuration.adoc[]
include::./common/chapters/gb.adoc[]
include::./common/chapters/control_if.adoc[]
//include::{srcdir}/chapters/counters.adoc[]
include::./common/chapters/port_numbers.adoc[]
include::./common/chapters/bibliography.adoc[]
include::./common/chapters/glossary.adoc[]
include::./common/chapters/gfdl.adoc[]

View File

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
ex:ts=2:sw=42sts=2:et
-*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
-->
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML 5.0//EN"
"http://docbook.org/xml/5.0/dtd/docbook.dtd" [
<!ENTITY chapter-vty SYSTEM "./common/chapters/vty.xml" >
<!ENTITY sections-vty SYSTEM "generated/docbook_osmogbproxy-vty-reference.xml" >
]>
<book>
<info>
<revhistory>
<revision>
<revnumber>v1</revnumber>
<date>2nd December 2019</date>
<authorinitials>hw</authorinitials>
<revremark>Initial</revremark>
</revision>
</revhistory>
<title>OsmoGbProxy VTY Reference</title>
<copyright>
<year>2019</year>
</copyright>
<legalnotice>
<para>This work is copyright by <orgname>sysmocom - s.f.m.c. GmbH</orgname>. All rights reserved.
</para>
</legalnotice>
</info>
<!-- Main chapters-->
&chapter-vty;
</book>

View File

@ -61,12 +61,6 @@ interact_vty \
4245 \
osmo-sgsn -c "../examples/osmo-sgsn/osmo-sgsn.cfg"
interact_vty \
"update_vty_reference" \
"vty-osmogbproxy/gbproxy_vty_reference.xml" \
4246 \
osmo-gbproxy -c "../examples/osmo-gbproxy/osmo-gbproxy.cfg"
interact_vty \
"update_counters" \
"chapters/counters_generated.adoc" \

View File

@ -1,5 +0,0 @@
<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>
<node id='config-gbproxy'>
<description>Configure the Gb proxy</description>
</node>
</vtydoc>

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@ noinst_HEADERS = \
common.h \
crc24.h \
debug.h \
gb_proxy.h \
gprs_gb.h \
gprs_gb_parse.h \
gprs_gmm.h \

View File

@ -1,298 +0,0 @@
#ifndef _GB_PROXY_H
#define _GB_PROXY_H
#include <osmocom/core/msgb.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/fsm.h>
#include <osmocom/core/hashtable.h>
#include <osmocom/gsm/gsm23003.h>
#include <osmocom/gsm/gsm23236.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/vty/command.h>
#include <sys/types.h>
#include <regex.h>
#include <stdbool.h>
#define GBPROXY_INIT_VU_GEN_TX 256
#define GBPROXY_MAX_NR_SGSN 16
/* BVCI uses 16 bits */
#define BVC_LOG_CTX_FLAG (1<<17)
struct rate_ctr_group;
struct gprs_gb_parse_context;
struct tlv_parsed;
enum gbproxy_global_ctr {
GBPROX_GLOB_CTR_INV_BVCI,
GBPROX_GLOB_CTR_INV_LAI,
GBPROX_GLOB_CTR_INV_RAI,
GBPROX_GLOB_CTR_INV_NSEI,
GBPROX_GLOB_CTR_PROTO_ERR_BSS,
GBPROX_GLOB_CTR_PROTO_ERR_SGSN,
GBPROX_GLOB_CTR_NOT_SUPPORTED_BSS,
GBPROX_GLOB_CTR_NOT_SUPPORTED_SGSN,
GBPROX_GLOB_CTR_RESTART_RESET_SGSN,
GBPROX_GLOB_CTR_TX_ERR_SGSN,
GBPROX_GLOB_CTR_OTHER_ERR,
};
enum gbproxy_bvc_ctr {
GBPROX_PEER_CTR_BLOCKED,
GBPROX_PEER_CTR_UNBLOCKED,
GBPROX_PEER_CTR_DROPPED,
GBPROX_PEER_CTR_INV_NSEI,
GBPROX_PEER_CTR_TX_ERR,
GBPROX_PEER_CTR_LAST,
};
/* global gb-proxy configuration */
struct gbproxy_config {
/* NS instance of libosmogb */
struct gprs_ns2_inst *nsi;
struct {
/* percentage of BVC flow control advertised to each SGSN in the pool */
uint8_t bvc_fc_ratio;
/* NRI bitlen and usable NULL-NRI ranges */
uint8_t nri_bitlen;
struct osmo_nri_ranges *null_nri_ranges;
/* Used for testing: If not NULL then this SGSN is returned by
* gbproxy_sgsn_by_tlli() */
struct gbproxy_sgsn *nsf_override;
} pool;
/* hash table of all BSS side Gb peers */
DECLARE_HASHTABLE(bss_nses, 8);
/* hash table of all SGSN-side Gb peers */
DECLARE_HASHTABLE(sgsn_nses, 8);
/* hash table of all gbproxy_cell */
DECLARE_HASHTABLE(cells, 8);
/* tlli<->nse cache used to map SUSPEND/RESUME (N)ACKS */
struct {
DECLARE_HASHTABLE(entries, 10);
struct osmo_timer_list timer;
/* Time in seconds that the entries should be valid */
uint8_t timeout;
} tlli_cache;
/* imsi<->nse cache used for PAGING REJECT */
struct {
DECLARE_HASHTABLE(entries, 10);
struct osmo_timer_list timer;
/* Time in seconds that the entries should be valid */
uint8_t timeout;
} imsi_cache;
/* List of all SGSNs */
struct llist_head sgsns;
/* Counter */
struct rate_ctr_group *ctrg;
};
/* One Cell within the BSS: Links BSS-side BVC to SGSN-side BVCs */
struct gbproxy_cell {
/* linked to gbproxy_config.cells hashtable */
struct hlist_node list;
/* point back to the config */
struct gbproxy_config *cfg;
/* BVCI of PTP BVCs associated to this cell */
uint16_t bvci;
/* Routing Area that this BVC is part of (raw 04.08 encoding) */
uint8_t ra[6];
/* pointer to the BSS-side BVC */
struct gbproxy_bvc *bss_bvc;
/* pointers to SGSN-side BVC (one for each pool member) */
struct gbproxy_bvc *sgsn_bvc[GBPROXY_MAX_NR_SGSN];
};
/* One BVC inside an NSE */
struct gbproxy_bvc {
/* linked to gbproxy_nse.bvcs */
struct hlist_node list;
/* The NSE this BVC belongs to */
struct gbproxy_nse *nse;
/* PTP BVCI of this BVC */
uint16_t bvci;
/* Routing Area that this BVC is part of (raw 04.08 encoding) */
uint8_t ra[6];
/* Counter */
struct rate_ctr_group *ctrg;
/* the cell to which this BVC belongs */
struct gbproxy_cell *cell;
/* per-BVC FSM instance */
struct osmo_fsm_inst *fi;
};
/* one NS Entity that we interact with (BSS/PCU) */
struct gbproxy_nse {
/* linked to gbproxy_config.bss_nses */
struct hlist_node list;
/* point back to the config */
struct gbproxy_config *cfg;
/* NSEI of the NSE */
uint16_t nsei;
/* Are we facing towards a SGSN (true) or BSS (false) */
bool sgsn_facing;
/* List of all BVCs in this NSE */
DECLARE_HASHTABLE(bvcs, 10);
};
/* SGSN configuration such as pool options (only for NSE where sgsn_facing == true) */
struct gbproxy_sgsn {
/* linked to gbproxy_config.sgsns */
struct llist_head list;
/* The NSE belonging to this SGSN */
struct gbproxy_nse *nse;
/* Name of the SGSN */
char *name;
/* Pool configuration for the sgsn (only valid if sgsn_facing == true) */
struct {
bool allow_attach;
struct osmo_nri_ranges *nri_ranges;
} pool;
};
/* TLLI cache */
struct gbproxy_tlli_cache_entry {
/* linked to gbproxy_config.tlli_cache.entries */
struct hlist_node list;
/* TLLI of the entry */
uint32_t tlli;
/* When was this entry last seen */
time_t tstamp;
/* The Cell this TLLI was last seen */
struct gbproxy_nse *nse;
};
/* IMSI cache */
struct gbproxy_imsi_cache_entry {
/* linked to gbproxy_config.imsi_cache.entries */
struct hlist_node list;
/* IMSI of the entry */
char imsi[OSMO_IMSI_BUF_SIZE];
/* When was this entry last seen */
time_t tstamp;
/* The SGSN where the request came from */
struct gbproxy_nse *nse;
};
/* Convenience logging macros for NSE/BVC */
#define LOGPNSE_CAT(NSE, SUBSYS, LEVEL, FMT, ARGS...) \
LOGP(SUBSYS, LEVEL, "NSE(%05u/%s) " FMT, (NSE)->nsei, \
(NSE)->sgsn_facing ? "SGSN" : "BSS", ## ARGS)
#define LOGPNSE(NSE, LEVEL, FMT, ARGS...) \
LOGPNSE_CAT(NSE, DGPRS, LEVEL, FMT, ## ARGS)
#define LOGPBVC_CAT(BVC, SUBSYS, LEVEL, FMT, ARGS...) \
LOGP(SUBSYS, LEVEL, "NSE(%05u/%s)-BVC(%05u/%s) " FMT, (BVC)->nse->nsei, \
(BVC)->nse->sgsn_facing ? "SGSN" : "BSS", (BVC)->bvci, \
osmo_fsm_inst_state_name((BVC)->fi), ## ARGS)
#define LOGPBVC(BVC, LEVEL, FMT, ARGS...) \
LOGPBVC_CAT(BVC, DGPRS, LEVEL, FMT, ## ARGS)
#define LOGPCELL_CAT(CELL, SUBSYS, LEVEL, FMT, ARGS...) \
LOGP(SUBSYS, LEVEL, "CELL(%05u) " FMT, (CELL)->bvci, ## ARGS)
#define LOGPCELL(CELL, LEVEL, FMT, ARGS...) \
LOGPCELL_CAT(CELL, DGPRS, LEVEL, FMT, ## ARGS)
#define LOGPSGSN_CAT(SGSN, SUBSYS, LEVEL, FMT, ARGS...) \
LOGP(SUBSYS, LEVEL, "NSE(%05u)-SGSN(%s) " FMT, (SGSN)->nse->nsei, (SGSN)->name, ## ARGS)
#define LOGPSGSN(SGSN, LEVEL, FMT, ARGS...) \
LOGPSGSN_CAT(SGSN, DGPRS, LEVEL, FMT, ## ARGS)
/* gb_proxy_vty .c */
int gbproxy_vty_init(void);
int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg);
/* gb_proxy_ctrl.c */
int gb_ctrl_cmds_install(void);
/* gb_proxy.c */
int gbproxy_init_config(struct gbproxy_config *cfg);
/* Main input function for Gb proxy */
int gbprox_rcvmsg(void *ctx, struct msgb *msg);
int gbprox_signal(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data);
int gprs_ns2_prim_cb(struct osmo_prim_hdr *oph, void *ctx);
void gbprox_reset(struct gbproxy_config *cfg);
/* Peer handling */
#define NSE_F_SGSN 0x0001
#define NSE_F_BSS 0x0002
struct gbproxy_bvc *gbproxy_bvc_by_bvci(struct gbproxy_nse *nse, uint16_t bvci);
struct gbproxy_bvc *gbproxy_bvc_alloc(struct gbproxy_nse *nse, uint16_t bvci);
void gbproxy_bvc_free(struct gbproxy_bvc *bvc);
int gbproxy_cleanup_bvcs(struct gbproxy_nse *nse, uint16_t bvci);
struct gbproxy_cell *gbproxy_cell_alloc(struct gbproxy_config *cfg, uint16_t bvci);
struct gbproxy_cell *gbproxy_cell_by_bvci(struct gbproxy_config *cfg, uint16_t bvci);
void gbproxy_cell_free(struct gbproxy_cell *cell);
bool gbproxy_cell_add_sgsn_bvc(struct gbproxy_cell *cell, struct gbproxy_bvc *bvc);
/* NSE handling */
struct gbproxy_nse *gbproxy_nse_alloc(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing);
void gbproxy_nse_free(struct gbproxy_nse *nse);
struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei, uint32_t flags);
struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing);
struct gbproxy_nse *gbproxy_nse_by_tlli(struct gbproxy_config *cfg, uint32_t tlli);
struct gbproxy_nse *gbproxy_nse_by_imsi(struct gbproxy_config *cfg, const char *imsi);
/* TLLI cache */
void gbproxy_tlli_cache_update(struct gbproxy_nse *nse, uint32_t tlli);
void gbproxy_tlli_cache_remove(struct gbproxy_config *cfg, uint32_t tlli);
int gbproxy_tlli_cache_cleanup(struct gbproxy_config *cfg);
/* IMSI cache */
void gbproxy_imsi_cache_update(struct gbproxy_nse *nse, const char *imsi);
void gbproxy_imsi_cache_remove(struct gbproxy_config *cfg, const char *imsi);
int gbproxy_imsi_cache_cleanup(struct gbproxy_config *cfg);
/* SGSN handling */
struct gbproxy_sgsn *gbproxy_sgsn_alloc(struct gbproxy_config *cfg, uint16_t nsei, const char *name);
void gbproxy_sgsn_free(struct gbproxy_sgsn *sgsn);
struct gbproxy_sgsn *gbproxy_sgsn_by_name(struct gbproxy_config *cfg, const char *name);
struct gbproxy_sgsn *gbproxy_sgsn_by_nsei(struct gbproxy_config *cfg, uint16_t nsei);
struct gbproxy_sgsn *gbproxy_sgsn_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei);
struct gbproxy_sgsn *gbproxy_sgsn_by_nri(struct gbproxy_config *cfg, uint16_t nri, bool *null_nri);
struct gbproxy_sgsn *gbproxy_sgsn_by_tlli(struct gbproxy_config *cfg, struct gbproxy_sgsn *sgsn_avoid,
uint32_t tlli);
#endif

View File

@ -16,18 +16,16 @@
app_configs = {
"gbproxy": ["doc/examples/osmo-gbproxy/osmo-gbproxy.cfg"],
"sgsn": ["doc/examples/osmo-sgsn/osmo-sgsn.cfg"],
"gtphub": ["doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg"]
}
apps = [(4246, "src/gbproxy/osmo-gbproxy", "OsmoGbProxy", "gbproxy"),
(4245, "src/sgsn/osmo-sgsn", "OsmoSGSN", "sgsn"),
apps = [(4245, "src/sgsn/osmo-sgsn", "OsmoSGSN", "sgsn"),
(4253, "src/gtphub/osmo-gtphub", "OsmoGTPhub", "gtphub")
]
vty_command = ["./src/sgsn/osmo-sgsn", "-c",
"doc/examples/osmo-sgsn/osmo-sgsn.cfg"]
vty_app = apps[1]
vty_app = apps[0]

View File

@ -1,6 +1,5 @@
SUBDIRS = \
gprs \
sgsn \
gbproxy \
gtphub \
$(NULL)

View File

@ -1,40 +0,0 @@
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/include \
-I$(top_builddir) \
$(NULL)
AM_CFLAGS = \
-Wall \
-fno-strict-aliasing \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOCTRL_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \
$(LIBOSMOGB_CFLAGS) \
$(LIBOSMOGSUPCLIENT_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(LIBGTP_CFLAGS) \
$(NULL)
bin_PROGRAMS = \
osmo-gbproxy \
$(NULL)
osmo_gbproxy_SOURCES = \
gb_proxy.c \
gb_proxy_main.c \
gb_proxy_vty.c \
gb_proxy_ctrl.c \
gb_proxy_peer.c \
$(NULL)
osmo_gbproxy_LDADD = \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMOGB_LIBS) \
$(LIBGTP_LIBS) \
-lrt \
$(NULL)

File diff suppressed because it is too large Load Diff

View File

@ -1,137 +0,0 @@
/* Control Interface Implementation for the Gb-proxy */
/*
* (C) 2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Daniel Willmann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/core/talloc.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/control_cmd.h>
#include <osmocom/sgsn/gb_proxy.h>
#include <osmocom/sgsn/debug.h>
extern vector ctrl_node_vec;
struct nsvc_cb_data {
struct ctrl_cmd *cmd;
uint16_t nsei;
bool is_sgsn;
};
static int ctrl_nsvc_state_cb(struct gprs_ns2_vc *nsvc, void *ctx) {
struct nsvc_cb_data *data = (struct nsvc_cb_data *)ctx;
struct ctrl_cmd *cmd = (struct ctrl_cmd *)data->cmd;
cmd->reply = talloc_asprintf_append(cmd->reply, "%u,%s,%s,%s\n",
data->nsei, gprs_ns2_ll_str(nsvc), gprs_ns2_nsvc_state_name(nsvc),
data->is_sgsn ? "SGSN" : "BSS" );
return 0;
}
static int get_nsvc_state(struct ctrl_cmd *cmd, void *data)
{
struct gbproxy_config *cfg = data;
struct gprs_ns2_inst *nsi = cfg->nsi;
struct gprs_ns2_nse *nse;
struct gbproxy_nse *nse_peer;
int i;
cmd->reply = talloc_strdup(cmd, "");
/* NS-VCs for SGSN */
hash_for_each(cfg->sgsn_nses, i, nse_peer, list) {
nse = gprs_ns2_nse_by_nsei(nsi, nse_peer->nsei);
if (nse)
gprs_ns2_nse_foreach_nsvc(nse, &ctrl_nsvc_state_cb, cmd);
}
/* NS-VCs for BSS peers */
hash_for_each(cfg->bss_nses, i, nse_peer, list) {
nse = gprs_ns2_nse_by_nsei(nsi, nse_peer->nsei);
if (nse)
gprs_ns2_nse_foreach_nsvc(nse, &ctrl_nsvc_state_cb, cmd);
}
return CTRL_CMD_REPLY;
}
CTRL_CMD_DEFINE_RO(nsvc_state, "nsvc-state");
static int get_gbproxy_state(struct ctrl_cmd *cmd, void *data)
{
struct gbproxy_config *cfg = data;
struct gbproxy_nse *nse_peer;
int i, j;
cmd->reply = talloc_strdup(cmd, "");
hash_for_each(cfg->bss_nses, i, nse_peer, list) {
struct gbproxy_bvc *bvc;
hash_for_each(nse_peer->bvcs, j, bvc, list) {
struct gprs_ra_id raid;
gsm48_parse_ra(&raid, bvc->ra);
cmd->reply = talloc_asprintf_append(cmd->reply, "%u,%u,%u,%u,%u,%u,%s\n",
nse_peer->nsei, bvc->bvci,
raid.mcc, raid.mnc,
raid.lac, raid.rac,
osmo_fsm_inst_state_name(bvc->fi));
}
}
return CTRL_CMD_REPLY;
}
CTRL_CMD_DEFINE_RO(gbproxy_state, "gbproxy-state");
static int get_num_peers(struct ctrl_cmd *cmd, void *data)
{
struct gbproxy_config *cfg = data;
struct gbproxy_nse *nse_peer;
struct gbproxy_bvc *bvc;
uint32_t count = 0;
int i, j;
hash_for_each(cfg->bss_nses, i, nse_peer, list) {
hash_for_each(nse_peer->bvcs, j, bvc, list)
count++;
}
cmd->reply = talloc_strdup(cmd, "");
cmd->reply = talloc_asprintf_append(cmd->reply, "%u", count);
return CTRL_CMD_REPLY;
}
CTRL_CMD_DEFINE_RO(num_peers, "number-of-peers");
int gb_ctrl_cmds_install(void)
{
int rc = 0;
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_nsvc_state);
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_gbproxy_state);
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_num_peers);
return rc;
}

View File

@ -1,336 +0,0 @@
/* NS-over-IP proxy */
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <signal.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <osmocom/core/application.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/sgsn/signal.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/vty.h>
#include <osmocom/sgsn/gb_proxy.h>
#include <osmocom/ctrl/control_vty.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/ports.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/stats.h>
#include <osmocom/vty/ports.h>
#include <osmocom/vty/misc.h>
#include "../../bscconfig.h"
#define _GNU_SOURCE
#include <getopt.h>
void *tall_sgsn_ctx;
const char *openbsc_copyright =
"Copyright (C) 2010 Harald Welte and On-Waves\r\n"
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
"This is free software: you are free to change and redistribute it.\r\n"
"There is NO WARRANTY, to the extent permitted by law.\r\n";
#define CONFIG_FILE_DEFAULT "osmo-gbproxy.cfg"
#define CONFIG_FILE_LEGACY "osmo_gbproxy.cfg"
static char *config_file = NULL;
struct gbproxy_config *gbcfg;
static int daemonize = 0;
/* Pointer to the SGSN peer */
extern struct gbprox_peer *gbprox_peer_sgsn;
static void signal_handler(int signum)
{
fprintf(stdout, "signal %u received\n", signum);
switch (signum) {
case SIGINT:
case SIGTERM:
osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
sleep(1);
exit(0);
break;
case SIGABRT:
/* in case of abort, we want to obtain a talloc report and
* then run default SIGABRT handler, who will generate coredump
* and abort the process. abort() should do this for us after we
* return, but program wouldn't exit if an external SIGABRT is
* received.
*/
talloc_report(tall_vty_ctx, stderr);
talloc_report_full(tall_sgsn_ctx, stderr);
signal(SIGABRT, SIG_DFL);
raise(SIGABRT);
break;
case SIGUSR1:
talloc_report(tall_vty_ctx, stderr);
talloc_report_full(tall_sgsn_ctx, stderr);
break;
case SIGUSR2:
talloc_report_full(tall_vty_ctx, stderr);
break;
default:
break;
}
}
static void print_usage()
{
printf("Usage: bsc_hack\n");
}
static void print_help()
{
printf(" Some useful help...\n");
printf(" -h --help this text\n");
printf(" -d option --debug=DNS:DGPRS,0:0 enable debugging\n");
printf(" -D --daemonize Fork the process into a background daemon\n");
printf(" -c --config-file filename The config file to use [%s]\n", CONFIG_FILE_DEFAULT);
printf(" -s --disable-color\n");
printf(" -T --timestamp Prefix every log line with a timestamp\n");
printf(" -V --version. Print the version.\n");
printf(" -e --log-level number. Set a global loglevel.\n");
}
static void handle_options(int argc, char **argv)
{
while (1) {
int option_index = 0, c;
static struct option long_options[] = {
{ "help", 0, 0, 'h' },
{ "debug", 1, 0, 'd' },
{ "daemonize", 0, 0, 'D' },
{ "config-file", 1, 0, 'c' },
{ "disable-color", 0, 0, 's' },
{ "timestamp", 0, 0, 'T' },
{ "version", 0, 0, 'V' },
{ "log-level", 1, 0, 'e' },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "hd:Dc:sTVe:",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'h':
print_usage();
print_help();
exit(0);
case 's':
log_set_use_color(osmo_stderr_target, 0);
break;
case 'd':
log_parse_category_mask(osmo_stderr_target, optarg);
break;
case 'D':
daemonize = 1;
break;
case 'c':
config_file = optarg;
break;
case 'T':
log_set_print_timestamp(osmo_stderr_target, 1);
break;
case 'e':
log_set_log_level(osmo_stderr_target, atoi(optarg));
break;
case 'V':
print_version(1);
exit(0);
break;
default:
break;
}
}
if (argc > optind) {
fprintf(stderr, "Unsupported positional arguments on command line\n");
exit(2);
}
}
static struct vty_app_info vty_info = {
.name = "OsmoGbProxy",
.version = PACKAGE_VERSION,
};
/* default categories */
static struct log_info_cat gprs_categories[] = {
[DGPRS] = {
.name = "DGPRS",
.description = "GPRS Packet Service",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DNS] = {
.name = "DNS",
.description = "GPRS Network Service (NS)",
.enabled = 1, .loglevel = LOGL_INFO,
},
[DOBJ] = {
.name = "DOBJ",
.description = "GbProxy object allocation/release",
.enabled = 1,
.color = "\033[38;5;121m"
},
};
static const struct log_info gprs_log_info = {
.filter_fn = gprs_log_filter_fn,
.cat = gprs_categories,
.num_cat = ARRAY_SIZE(gprs_categories),
};
static bool file_exists(const char *path)
{
struct stat sb;
return stat(path, &sb) ? false : true;
}
int gbprox_bssgp_send_cb(void *ctx, struct msgb *msg);
int main(int argc, char **argv)
{
int rc;
struct ctrl_handle *ctrl;
tall_sgsn_ctx = talloc_named_const(NULL, 0, "nsip_proxy");
msgb_talloc_ctx_init(tall_sgsn_ctx, 0);
vty_info.tall_ctx = tall_sgsn_ctx;
signal(SIGINT, &signal_handler);
signal(SIGTERM, &signal_handler);
signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
signal(SIGUSR2, &signal_handler);
osmo_init_ignore_signals();
osmo_init_logging2(tall_sgsn_ctx, &gprs_log_info);
vty_info.copyright = openbsc_copyright;
vty_init(&vty_info);
logging_vty_add_cmds();
osmo_talloc_vty_add_cmds();
osmo_stats_vty_add_cmds();
osmo_fsm_vty_add_cmds();
gbproxy_vty_init();
handle_options(argc, argv);
/* Backwards compatibility: for years, the default config file name was
* osmo_gbproxy.cfg. All other Osmocom programs use osmo-*.cfg with a
* dash. To be able to use the new config file name without breaking
* previous setups that might rely on the legacy default config file
* name, we need to look for the old config file if no -c option was
* passed AND no file exists with the new default file name. */
if (!config_file) {
/* No -c option was passed */
if (file_exists(CONFIG_FILE_LEGACY)
&& !file_exists(CONFIG_FILE_DEFAULT))
config_file = CONFIG_FILE_LEGACY;
else
config_file = CONFIG_FILE_DEFAULT;
}
rate_ctr_init(tall_sgsn_ctx);
osmo_stats_init(tall_sgsn_ctx);
gbcfg = talloc_zero(tall_sgsn_ctx, struct gbproxy_config);
if (!gbcfg) {
LOGP(DGPRS, LOGL_FATAL, "Unable to allocate config\n");
exit(1);
}
gbproxy_init_config(gbcfg);
gbcfg->nsi = gprs_ns2_instantiate(tall_sgsn_ctx, gprs_ns2_prim_cb, gbcfg);
if (!gbcfg->nsi) {
LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
exit(1);
}
gprs_ns2_vty_init(gbcfg->nsi);
logging_vty_add_deprecated_subsys(tall_sgsn_ctx, "bssgp");
bssgp_set_bssgp_callback(gbprox_bssgp_send_cb, gbcfg);
rc = gbproxy_parse_config(config_file, gbcfg);
if (rc < 0) {
LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file '%s'\n", config_file);
exit(2);
}
/* start telnet after reading config for vty_get_bind_addr() */
rc = telnet_init_dynif(tall_sgsn_ctx, NULL,
vty_get_bind_addr(), OSMO_VTY_PORT_GBPROXY);
if (rc < 0)
exit(1);
/* Start control interface after getting config for
* ctrl_vty_get_bind_addr() */
ctrl = ctrl_interface_setup_dynip(gbcfg, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_GBPROXY, NULL);
if (!ctrl) {
LOGP(DGPRS, LOGL_FATAL, "Failed to create CTRL interface.\n");
exit(1);
}
if (gb_ctrl_cmds_install() != 0) {
LOGP(DGPRS, LOGL_FATAL, "Failed to install CTRL commands.\n");
exit(1);
}
if (daemonize) {
rc = osmo_daemonize();
if (rc < 0) {
perror("Error during daemonize");
exit(1);
}
}
while (1) {
rc = osmo_select_main(0);
if (rc < 0)
exit(3);
}
exit(0);
}

View File

@ -1,759 +0,0 @@
/* Gb proxy peer handling */
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2010-2013 by On-Waves
* (C) 2013 by Holger Hans Peter Freyther
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/sgsn/gb_proxy.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/gprs/protocol/gsm_08_18.h>
#include <osmocom/core/crc16.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/tlv.h>
#include <string.h>
extern void *tall_sgsn_ctx;
static const struct rate_ctr_desc bvc_ctr_description[] = {
{ "blocked", "BVC Block " },
{ "unblocked", "BVC Unblock " },
{ "dropped", "BVC blocked, dropped packet " },
{ "inv-nsei", "NSEI mismatch " },
{ "tx-err", "NS Transmission error " },
};
osmo_static_assert(ARRAY_SIZE(bvc_ctr_description) == GBPROX_PEER_CTR_LAST, everything_described);
static const struct rate_ctr_group_desc bvc_ctrg_desc = {
.group_name_prefix = "gbproxy:peer",
.group_description = "GBProxy Peer Statistics",
.num_ctr = ARRAY_SIZE(bvc_ctr_description),
.ctr_desc = bvc_ctr_description,
.class_id = OSMO_STATS_CLASS_PEER,
};
/* Find the gbproxy_bvc by its BVCI. There can only be one match */
struct gbproxy_bvc *gbproxy_bvc_by_bvci(struct gbproxy_nse *nse, uint16_t bvci)
{
struct gbproxy_bvc *bvc;
hash_for_each_possible(nse->bvcs, bvc, list, bvci) {
if (bvc->bvci == bvci)
return bvc;
}
return NULL;
}
struct gbproxy_bvc *gbproxy_bvc_alloc(struct gbproxy_nse *nse, uint16_t bvci)
{
struct gbproxy_bvc *bvc;
OSMO_ASSERT(nse);
struct gbproxy_config *cfg = nse->cfg;
OSMO_ASSERT(cfg);
bvc = talloc_zero(tall_sgsn_ctx, struct gbproxy_bvc);
if (!bvc)
return NULL;
bvc->bvci = bvci;
bvc->ctrg = rate_ctr_group_alloc(bvc, &bvc_ctrg_desc, (nse->nsei << 16) | bvci);
if (!bvc->ctrg) {
talloc_free(bvc);
return NULL;
}
bvc->nse = nse;
hash_add(nse->bvcs, &bvc->list, bvc->bvci);
LOGPBVC_CAT(bvc, DOBJ, LOGL_INFO, "BVC Created\n");
/* We leave allocating the bvc->fi to the caller, as the FSM details depend
* on the type of BVC (SIG/PTP) and role (SGSN/BSS) */
return bvc;
}
void gbproxy_bvc_free(struct gbproxy_bvc *bvc)
{
struct gbproxy_cell *cell;
if (!bvc)
return;
LOGPBVC_CAT(bvc, DOBJ, LOGL_INFO, "BVC Destroying\n");
hash_del(&bvc->list);
rate_ctr_group_free(bvc->ctrg);
bvc->ctrg = NULL;
osmo_fsm_inst_free(bvc->fi);
cell = bvc->cell;
if (cell) {
int i;
if (cell->bss_bvc == bvc)
cell->bss_bvc = NULL;
/* we could also be a SGSN-side BVC */
for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {
if (cell->sgsn_bvc[i] == bvc)
cell->sgsn_bvc[i] = NULL;
}
bvc->cell = NULL;
}
talloc_free(bvc);
}
/*! remove BVCs on NSE specified by NSEI.
* \param[in] cfg proxy in which we operate
* \param[in] nsei NS entity in which we should clean up
* \param[in] bvci if 0: remove all PTP BVCs; if != 0: BVCI of the single BVC to clean up */
int gbproxy_cleanup_bvcs(struct gbproxy_nse *nse, uint16_t bvci)
{
struct hlist_node *btmp;
struct gbproxy_bvc *bvc;
int j, counter = 0;
if (!nse)
return 0;
hash_for_each_safe(nse->bvcs, j, btmp, bvc, list) {
if (bvci && bvc->bvci != bvci)
continue;
if (bvci == 0 && bvc->bvci == 0)
continue;
gbproxy_bvc_free(bvc);
counter += 1;
}
return counter;
}
/***********************************************************************
* CELL
***********************************************************************/
/* Allocate a new 'cell' object */
struct gbproxy_cell *gbproxy_cell_alloc(struct gbproxy_config *cfg, uint16_t bvci)
{
struct gbproxy_cell *cell;
OSMO_ASSERT(cfg);
cell = talloc_zero(cfg, struct gbproxy_cell);
if (!cell)
return NULL;
cell->cfg = cfg;
cell->bvci = bvci;
hash_add(cfg->cells, &cell->list, cell->bvci);
LOGPCELL_CAT(cell, DOBJ, LOGL_INFO, "CELL Created\n");
return cell;
}
/* Find cell by BVCI */
struct gbproxy_cell *gbproxy_cell_by_bvci(struct gbproxy_config *cfg, uint16_t bvci)
{
struct gbproxy_cell *cell;
hash_for_each_possible(cfg->cells, cell, list, bvci) {
if (cell->bvci == bvci)
return cell;
}
return NULL;
}
struct gbproxy_cell *gbproxy_cell_by_bvci_or_new(struct gbproxy_config *cfg, uint16_t bvci)
{
struct gbproxy_cell *cell;
OSMO_ASSERT(cfg);
cell = gbproxy_cell_by_bvci(cfg, bvci);
if (!cell)
cell = gbproxy_cell_alloc(cfg, bvci);
return cell;
}
void gbproxy_cell_free(struct gbproxy_cell *cell)
{
unsigned int i;
if (!cell)
return;
LOGPCELL_CAT(cell, DOBJ, LOGL_INFO, "CELL Destroying\n");
/* remove from cfg.cells */
hash_del(&cell->list);
/* remove back-pointers from the BSS side */
if (cell->bss_bvc && cell->bss_bvc->cell)
cell->bss_bvc->cell = NULL;
/* remove back-pointers from the SGSN side */
for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {
if (!cell->sgsn_bvc[i])
continue;
if (cell->sgsn_bvc[i]->cell)
cell->sgsn_bvc[i]->cell = NULL;
}
talloc_free(cell);
}
bool gbproxy_cell_add_sgsn_bvc(struct gbproxy_cell *cell, struct gbproxy_bvc *bvc)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {
if (!cell->sgsn_bvc[i]) {
cell->sgsn_bvc[i] = bvc;
LOGPCELL_CAT(cell, DOBJ, LOGL_DEBUG, "CELL linked to SGSN\n");
LOGPBVC_CAT(bvc, DOBJ, LOGL_DEBUG, "BVC linked to CELL\n");
return true;
}
}
return false;
}
/***********************************************************************
* TLLI cache
***********************************************************************/
static inline struct gbproxy_tlli_cache_entry *_get_tlli_entry(struct gbproxy_config *cfg, uint32_t tlli)
{
struct gbproxy_tlli_cache_entry *cache_entry;
hash_for_each_possible(cfg->tlli_cache.entries, cache_entry, list, tlli) {
if (cache_entry->tlli == tlli)
return cache_entry;
}
return NULL;
}
void gbproxy_tlli_cache_update(struct gbproxy_nse *nse, uint32_t tlli)
{
struct gbproxy_config *cfg = nse->cfg;
struct timespec now;
struct gbproxy_tlli_cache_entry *cache_entry = _get_tlli_entry(cfg, tlli);
osmo_clock_gettime(CLOCK_MONOTONIC, &now);
if (cache_entry) {
/* Update the entry if it already exists */
cache_entry->nse = nse;
cache_entry->tstamp = now.tv_sec;
return;
}
cache_entry = talloc_zero(cfg, struct gbproxy_tlli_cache_entry);
cache_entry->tlli = tlli;
cache_entry->nse = nse;
cache_entry->tstamp = now.tv_sec;
hash_add(cfg->tlli_cache.entries, &cache_entry->list, cache_entry->tlli);
}
static void _tlli_cache_remove_nse(struct gbproxy_nse *nse) {
uint i;
struct gbproxy_config *cfg = nse->cfg;
struct gbproxy_tlli_cache_entry *tlli_cache;
struct hlist_node *tmp;
hash_for_each_safe(cfg->tlli_cache.entries, i, tmp, tlli_cache, list) {
if (tlli_cache->nse == nse) {
hash_del(&tlli_cache->list);
talloc_free(tlli_cache);
}
}
}
void gbproxy_tlli_cache_remove(struct gbproxy_config *cfg, uint32_t tlli)
{
struct gbproxy_tlli_cache_entry *tlli_cache;
struct hlist_node *tmp;
hash_for_each_possible_safe(cfg->tlli_cache.entries, tlli_cache, tmp, list, tlli) {
if (tlli_cache->tlli == tlli) {
hash_del(&tlli_cache->list);
talloc_free(tlli_cache);
return;
}
}
}
int gbproxy_tlli_cache_cleanup(struct gbproxy_config *cfg)
{
int i, count = 0;
struct gbproxy_tlli_cache_entry *tlli_cache;
struct hlist_node *tmp;
struct timespec now;
time_t expiry;
osmo_clock_gettime(CLOCK_MONOTONIC, &now);
expiry = now.tv_sec - cfg->tlli_cache.timeout;
hash_for_each_safe(cfg->tlli_cache.entries, i, tmp, tlli_cache, list) {
if (tlli_cache->tstamp < expiry) {
count++;
LOGP(DGPRS, LOGL_NOTICE, "Cache entry for TLLI %08x expired, removing\n", tlli_cache->tlli);
hash_del(&tlli_cache->list);
talloc_free(tlli_cache);
}
}
return count;
}
/***********************************************************************
* IMSI cache
***********************************************************************/
static inline uint16_t _checksum_imsi(const char *imsi)
{
size_t len = strlen(imsi);
return osmo_crc16(0, (const uint8_t *)imsi, len);
}
static inline struct gbproxy_imsi_cache_entry *_get_imsi_entry(struct gbproxy_config *cfg, const char *imsi)
{
struct gbproxy_imsi_cache_entry *cache_entry;
uint16_t imsi_hash = _checksum_imsi(imsi);
hash_for_each_possible(cfg->imsi_cache.entries, cache_entry, list, imsi_hash) {
if (!strncmp(cache_entry->imsi, imsi, sizeof(cache_entry->imsi)))
return cache_entry;
}
return NULL;
}
void gbproxy_imsi_cache_update(struct gbproxy_nse *nse, const char *imsi)
{
struct gbproxy_config *cfg = nse->cfg;
struct timespec now;
struct gbproxy_imsi_cache_entry *cache_entry = _get_imsi_entry(cfg, imsi);
uint16_t imsi_hash = _checksum_imsi(imsi);
osmo_clock_gettime(CLOCK_MONOTONIC, &now);
if (cache_entry) {
/* Update the entry if it already exists */
cache_entry->nse = nse;
cache_entry->tstamp = now.tv_sec;
return;
}
cache_entry = talloc_zero(cfg, struct gbproxy_imsi_cache_entry);
OSMO_STRLCPY_ARRAY(cache_entry->imsi, imsi);
cache_entry->nse = nse;
cache_entry->tstamp = now.tv_sec;
hash_add(cfg->imsi_cache.entries, &cache_entry->list, imsi_hash);
}
static void _imsi_cache_remove_nse(struct gbproxy_nse *nse) {
uint i;
struct gbproxy_config *cfg = nse->cfg;
struct gbproxy_imsi_cache_entry *imsi_cache;
struct hlist_node *tmp;
hash_for_each_safe(cfg->imsi_cache.entries, i, tmp, imsi_cache, list) {
if (imsi_cache->nse == nse) {
hash_del(&imsi_cache->list);
talloc_free(imsi_cache);
}
}
}
void gbproxy_imsi_cache_remove(struct gbproxy_config *cfg, const char *imsi)
{
struct gbproxy_imsi_cache_entry *imsi_cache;
struct hlist_node *tmp;
uint16_t imsi_hash = _checksum_imsi(imsi);
hash_for_each_possible_safe(cfg->imsi_cache.entries, imsi_cache, tmp, list, imsi_hash) {
if (!(strncmp(imsi_cache->imsi, imsi, sizeof(imsi_cache->imsi)))) {
hash_del(&imsi_cache->list);
talloc_free(imsi_cache);
return;
}
}
}
int gbproxy_imsi_cache_cleanup(struct gbproxy_config *cfg)
{
int i, count = 0;
struct gbproxy_imsi_cache_entry *imsi_cache;
struct hlist_node *tmp;
struct timespec now;
time_t expiry;
osmo_clock_gettime(CLOCK_MONOTONIC, &now);
expiry = now.tv_sec - cfg->imsi_cache.timeout;
hash_for_each_safe(cfg->imsi_cache.entries, i, tmp, imsi_cache, list) {
if (imsi_cache->tstamp < expiry) {
count++;
LOGP(DGPRS, LOGL_NOTICE, "Cache entry for IMSI %s expired, removing\n", imsi_cache->imsi);
hash_del(&imsi_cache->list);
talloc_free(imsi_cache);
}
}
return count;
}
/***********************************************************************
* NSE - NS Entity
***********************************************************************/
struct gbproxy_nse *gbproxy_nse_alloc(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing)
{
struct gbproxy_nse *nse;
OSMO_ASSERT(cfg);
nse = talloc_zero(tall_sgsn_ctx, struct gbproxy_nse);
if (!nse)
return NULL;
nse->nsei = nsei;
nse->cfg = cfg;
nse->sgsn_facing = sgsn_facing;
if (sgsn_facing)
hash_add(cfg->sgsn_nses, &nse->list, nsei);
else
hash_add(cfg->bss_nses, &nse->list, nsei);
hash_init(nse->bvcs);
LOGPNSE_CAT(nse, DOBJ, LOGL_INFO, "NSE Created\n");
return nse;
}
static void _nse_free(struct gbproxy_nse *nse)
{
struct gbproxy_bvc *bvc;
struct hlist_node *tmp;
int i;
if (!nse)
return;
LOGPNSE_CAT(nse, DOBJ, LOGL_INFO, "NSE Destroying\n");
hash_del(&nse->list);
/* Clear the cache entries of this NSE */
_tlli_cache_remove_nse(nse);
_imsi_cache_remove_nse(nse);
hash_for_each_safe(nse->bvcs, i, tmp, bvc, list)
gbproxy_bvc_free(bvc);
talloc_free(nse);
}
static void _sgsn_free(struct gbproxy_sgsn *sgsn);
void gbproxy_nse_free(struct gbproxy_nse *nse)
{
if (!nse)
return;
OSMO_ASSERT(nse->cfg);
if (nse->sgsn_facing) {
struct gbproxy_sgsn *sgsn = gbproxy_sgsn_by_nsei(nse->cfg, nse->nsei);
OSMO_ASSERT(sgsn);
_sgsn_free(sgsn);
}
_nse_free(nse);
}
struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei, uint32_t flags)
{
struct gbproxy_nse *nse;
OSMO_ASSERT(cfg);
if (flags & NSE_F_SGSN) {
hash_for_each_possible(cfg->sgsn_nses, nse, list, nsei) {
if (nse->nsei == nsei)
return nse;
}
}
if (flags & NSE_F_BSS) {
hash_for_each_possible(cfg->bss_nses, nse, list, nsei) {
if (nse->nsei == nsei)
return nse;
}
}
return NULL;
}
struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing)
{
struct gbproxy_nse *nse;
OSMO_ASSERT(cfg);
nse = gbproxy_nse_by_nsei(cfg, nsei, sgsn_facing ? NSE_F_SGSN : NSE_F_BSS);
if (!nse)
nse = gbproxy_nse_alloc(cfg, nsei, sgsn_facing);
return nse;
}
struct gbproxy_nse *gbproxy_nse_by_tlli(struct gbproxy_config *cfg, uint32_t tlli)
{
struct gbproxy_tlli_cache_entry *tlli_cache;
hash_for_each_possible(cfg->tlli_cache.entries, tlli_cache, list, tlli) {
if (tlli_cache->tlli == tlli)
return tlli_cache->nse;
}
return NULL;
}
struct gbproxy_nse *gbproxy_nse_by_imsi(struct gbproxy_config *cfg, const char *imsi)
{
struct gbproxy_imsi_cache_entry *imsi_cache;
uint16_t imsi_hash = _checksum_imsi(imsi);
hash_for_each_possible(cfg->imsi_cache.entries, imsi_cache, list, imsi_hash) {
if (!strncmp(imsi_cache->imsi, imsi, sizeof(imsi_cache->imsi)))
return imsi_cache->nse;
}
return NULL;
}
/***********************************************************************
* SGSN - Serving GPRS Support Node
***********************************************************************/
/*! Allocate a new SGSN. This ensures the corresponding gbproxy_nse is allocated as well
* \param[in] cfg The gbproxy configuration
* \param[in] nsei The nsei where the SGSN can be reached
* \param[in] name A name to give the SGSN
* \return The SGSN, NULL if it couldn't be allocated
*/
struct gbproxy_sgsn *gbproxy_sgsn_alloc(struct gbproxy_config *cfg, uint16_t nsei, const char *name)
{
struct gbproxy_sgsn *sgsn;
OSMO_ASSERT(cfg);
sgsn = talloc_zero(tall_sgsn_ctx, struct gbproxy_sgsn);
if (!sgsn)
return NULL;
sgsn->nse = gbproxy_nse_alloc(cfg, nsei, true);
if (!sgsn->nse) {
LOGP(DOBJ, LOGL_ERROR, "Could not allocate NSE(%05u) for SGSN(%s)\n",
nsei, sgsn->name);
goto free_sgsn;
}
if (name)
sgsn->name = talloc_strdup(sgsn, name);
else
sgsn->name = talloc_asprintf(sgsn, "NSE(%05u)", sgsn->nse->nsei);
if (!sgsn->name)
goto free_sgsn;
sgsn->pool.allow_attach = true;
sgsn->pool.nri_ranges = osmo_nri_ranges_alloc(sgsn);
llist_add_tail(&sgsn->list, &cfg->sgsns);
LOGPSGSN_CAT(sgsn, DOBJ, LOGL_INFO, "SGSN Created\n");
return sgsn;
free_sgsn:
talloc_free(sgsn);
return NULL;
}
/* Only free gbproxy_sgsn, sgsn can't be NULL */
static void _sgsn_free(struct gbproxy_sgsn *sgsn) {
struct gbproxy_config *cfg;
OSMO_ASSERT(sgsn->nse);
cfg = sgsn->nse->cfg;
OSMO_ASSERT(cfg);
LOGPSGSN_CAT(sgsn, DOBJ, LOGL_INFO, "SGSN Destroying\n");
llist_del(&sgsn->list);
/* talloc will free ->name and ->pool.nri_ranges */
talloc_free(sgsn);
}
/*! Free the SGSN. This ensures the corresponding gbproxy_nse is freed as well
* \param[in] sgsn The SGSN
*/
void gbproxy_sgsn_free(struct gbproxy_sgsn *sgsn)
{
if (!sgsn)
return;
OSMO_ASSERT(sgsn->nse)
_nse_free(sgsn->nse);
_sgsn_free(sgsn);
}
/*! Return the SGSN for a given NSEI
* \param[in] cfg The gbproxy configuration
* \param[in] nsei The nsei where the SGSN can be reached
* \return Returns the matching SGSN or NULL if it couldn't be found
*/
struct gbproxy_sgsn *gbproxy_sgsn_by_name(struct gbproxy_config *cfg, const char *name)
{
struct gbproxy_sgsn *sgsn;
OSMO_ASSERT(cfg);
llist_for_each_entry(sgsn, &cfg->sgsns, list) {
if (!strcmp(sgsn->name, name))
return sgsn;
}
return NULL;
}
/*! Return the SGSN for a given NSEI
* \param[in] cfg The gbproxy configuration
* \param[in] nsei The nsei where the SGSN can be reached
* \return Returns the matching SGSN or NULL if it couldn't be found
*/
struct gbproxy_sgsn *gbproxy_sgsn_by_nsei(struct gbproxy_config *cfg, uint16_t nsei)
{
struct gbproxy_sgsn *sgsn;
OSMO_ASSERT(cfg);
llist_for_each_entry(sgsn, &cfg->sgsns, list) {
if (sgsn->nse->nsei == nsei)
return sgsn;
}
return NULL;
}
/*! Return the SGSN for a given NSEI, creating a new one if none exists
* \param[in] cfg The gbproxy configuration
* \param[in] nsei The nsei where the SGSN can be reached
* \return Returns the SGSN
*/
struct gbproxy_sgsn *gbproxy_sgsn_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei)
{
struct gbproxy_sgsn *sgsn;
OSMO_ASSERT(cfg);
sgsn = gbproxy_sgsn_by_nsei(cfg, nsei);
if (!sgsn)
sgsn = gbproxy_sgsn_alloc(cfg, nsei, NULL);
return sgsn;
}
/*! Return the gbproxy_sgsn matching that NRI
* \param[in] cfg proxy in which we operate
* \param[in] nri NRI to look for
* \param[out] null_nri If not NULL this indicates whether the NRI is a null NRI
* \return The SGSN this NRI has been added to, NULL if no matching SGSN could be found
*/
struct gbproxy_sgsn *gbproxy_sgsn_by_nri(struct gbproxy_config *cfg, uint16_t nri, bool *null_nri)
{
struct gbproxy_sgsn *sgsn;
OSMO_ASSERT(cfg);
llist_for_each_entry(sgsn, &cfg->sgsns, list) {
if (osmo_nri_v_matches_ranges(nri, sgsn->pool.nri_ranges)) {
/* Also check if the NRI we're looking for is a NULL NRI */
if (null_nri) {
if (osmo_nri_v_matches_ranges(nri, cfg->pool.null_nri_ranges))
*null_nri = true;
else
*null_nri = false;
}
return sgsn;
}
}
return NULL;
}
/*! Seleect a pseudo-random SGSN for a given TLLI, ignoring any SGSN that is not accepting connections
* \param[in] cfg The gbproxy configuration
* \param[in] sgsn_avoid If not NULL then avoid this SGSN when selecting a new one. Use for load redistribution
* \param[in] tlli The tlli to choose an SGSN for. The same tlli will map to the same SGSN as long as no SGSN is
* added/removed or allow_attach changes.
* \return Returns the sgsn on success, NULL if no SGSN that allows new connections could be found
*/
struct gbproxy_sgsn *gbproxy_sgsn_by_tlli(struct gbproxy_config *cfg, struct gbproxy_sgsn *sgsn_avoid,
uint32_t tlli)
{
uint32_t i = 0;
uint32_t index, num_sgsns;
OSMO_ASSERT(cfg);
struct gbproxy_sgsn *sgsn = cfg->pool.nsf_override;
if (sgsn) {
LOGPSGSN(sgsn, LOGL_DEBUG, "Node selection function is overridden by config\n");
return sgsn;
}
/* TODO: We should keep track of count in cfg */
num_sgsns = llist_count(&cfg->sgsns);
if (num_sgsns == 0)
return NULL;
/* FIXME: 256 SGSNs ought to be enough for everyone */
index = hash_32(tlli, 8) % num_sgsns;
/* Get the first enabled SGSN after index */
llist_for_each_entry(sgsn, &cfg->sgsns, list) {
if (i >= index && sgsn->pool.allow_attach) {
return sgsn;
}
i++;
}
/* Start again from the beginning */
i = 0;
llist_for_each_entry(sgsn, &cfg->sgsns, list) {
if (i >= index) {
break;
} else if (sgsn->pool.allow_attach) {
return sgsn;
}
i++;
}
return NULL;
}

View File

@ -1,778 +0,0 @@
/*
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <time.h>
#include <inttypes.h>
#include <osmocom/core/hashtable.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/utils.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/gprs/bssgp_bvc_fsm.h>
#include <osmocom/gsm/apn.h>
#include <osmocom/gsm/gsm23236.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gb_proxy.h>
#include <osmocom/sgsn/gprs_utils.h>
#include <osmocom/sgsn/vty.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/vty.h>
#include <osmocom/vty/misc.h>
#define GBPROXY_STR "Display information about the Gb proxy\n"
#define NRI_STR "Mapping of Network Resource Indicators to this SGSN, for SGSN pooling\n"
#define NULL_NRI_STR "Define NULL-NRI values that cause re-assignment of an MS to a different SGSN, for SGSN pooling.\n"
#define NRI_FIRST_LAST_STR "First value of the NRI value range, should not surpass the configured 'nri bitlen'.\n" \
"Last value of the NRI value range, should not surpass the configured 'nri bitlen' and be larger than the" \
" first value; if omitted, apply only the first value.\n"
#define NRI_ARGS_TO_STR_FMT "%s%s%s"
#define NRI_ARGS_TO_STR_ARGS(ARGC, ARGV) ARGV[0], (ARGC>1)? ".." : "", (ARGC>1)? ARGV[1] : ""
#define NRI_WARN(SGSN, FORMAT, args...) do { \
vty_out(vty, "%% Warning: NSE(%05d/SGSN): " FORMAT "%s", (SGSN)->nse->nsei, ##args, VTY_NEWLINE); \
LOGP(DLBSSGP, LOGL_ERROR, "NSE(%05d/SGSN): " FORMAT "\n", (SGSN)->nse->nsei, ##args); \
} while (0)
static struct gbproxy_config *g_cfg = NULL;
/*
* vty code for gbproxy below
*/
static struct cmd_node gbproxy_node = {
GBPROXY_NODE,
"%s(config-gbproxy)# ",
1,
};
static void gbprox_vty_print_bvc(struct vty *vty, struct gbproxy_bvc *bvc)
{
if (bvc->bvci == 0) {
vty_out(vty, "NSEI %5u, SIG-BVCI %5u [%s]%s", bvc->nse->nsei, bvc->bvci,
osmo_fsm_inst_state_name(bvc->fi), VTY_NEWLINE);
} else {
struct gprs_ra_id raid;
gsm48_parse_ra(&raid, bvc->ra);
vty_out(vty, "NSEI %5u, PTP-BVCI %5u, RAI %s [%s]%s", bvc->nse->nsei, bvc->bvci,
osmo_rai_name(&raid), osmo_fsm_inst_state_name(bvc->fi), VTY_NEWLINE);
}
}
static void gbproxy_vty_print_nse(struct vty *vty, struct gbproxy_nse *nse, bool show_stats)
{
struct gbproxy_bvc *bvc;
int j;
hash_for_each(nse->bvcs, j, bvc, list) {
gbprox_vty_print_bvc(vty, bvc);
if (show_stats)
vty_out_rate_ctr_group(vty, " ", bvc->ctrg);
}
}
static void gbproxy_vty_print_cell(struct vty *vty, struct gbproxy_cell *cell, bool show_stats)
{
struct gprs_ra_id raid;
gsm48_parse_ra(&raid, cell->ra);
unsigned int num_sgsn_bvc = 0;
unsigned int i;
vty_out(vty, "BVCI %5u RAI %s: ", cell->bvci, osmo_rai_name(&raid));
if (cell->bss_bvc)
vty_out(vty, "BSS NSEI %5u, SGSN NSEI ", cell->bss_bvc->nse->nsei);
else
vty_out(vty, "BSS NSEI <none>, SGSN NSEI ");
for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {
struct gbproxy_bvc *sgsn_bvc = cell->sgsn_bvc[i];
if (sgsn_bvc) {
vty_out(vty, "%5u ", sgsn_bvc->nse->nsei);
num_sgsn_bvc++;
}
}
if (num_sgsn_bvc)
vty_out(vty, "%s", VTY_NEWLINE);
else
vty_out(vty, "<none>%s", VTY_NEWLINE);
}
static int config_write_gbproxy(struct vty *vty)
{
struct osmo_nri_range *r;
vty_out(vty, "gbproxy%s", VTY_NEWLINE);
if (g_cfg->pool.bvc_fc_ratio != 100)
vty_out(vty, " pool bvc-flow-control-ratio %u%s", g_cfg->pool.bvc_fc_ratio, VTY_NEWLINE);
if (g_cfg->pool.nri_bitlen != OSMO_NRI_BITLEN_DEFAULT)
vty_out(vty, " nri bitlen %u%s", g_cfg->pool.nri_bitlen, VTY_NEWLINE);
llist_for_each_entry(r, &g_cfg->pool.null_nri_ranges->entries, entry) {
vty_out(vty, " nri null add %d", r->first);
if (r->first != r->last)
vty_out(vty, " %d", r->last);
vty_out(vty, "%s", VTY_NEWLINE);
}
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy,
cfg_gbproxy_cmd,
"gbproxy",
"Configure the Gb proxy")
{
vty->node = GBPROXY_NODE;
return CMD_SUCCESS;
}
/* VTY code for SGSN (pool) configuration */
extern const struct bssgp_bvc_fsm_ops sgsn_sig_bvc_fsm_ops;
#include <osmocom/gprs/protocol/gsm_08_18.h>
static struct cmd_node sgsn_node = {
SGSN_NODE,
"%s(config-sgsn)# ",
1,
};
static void sgsn_write_nri(struct vty *vty, struct gbproxy_sgsn *sgsn, bool verbose)
{
struct osmo_nri_range *r;
if (verbose) {
vty_out(vty, "sgsn nsei %d%s", sgsn->nse->nsei, VTY_NEWLINE);
if (llist_empty(&sgsn->pool.nri_ranges->entries)) {
vty_out(vty, " %% no NRI mappings%s", VTY_NEWLINE);
return;
}
}
llist_for_each_entry(r, &sgsn->pool.nri_ranges->entries, entry) {
if (osmo_nri_range_validate(r, 255))
vty_out(vty, " %% INVALID RANGE:");
vty_out(vty, " nri add %d", r->first);
if (r->first != r->last)
vty_out(vty, " %d", r->last);
vty_out(vty, "%s", VTY_NEWLINE);
}
}
static void write_sgsn(struct vty *vty, struct gbproxy_sgsn *sgsn)
{
vty_out(vty, "sgsn nsei %u%s", sgsn->nse->nsei, VTY_NEWLINE);
vty_out(vty, " name %s%s", sgsn->name, VTY_NEWLINE);
vty_out(vty, " %sallow-attach%s", sgsn->pool.allow_attach ? "" : "no ", VTY_NEWLINE);
sgsn_write_nri(vty, sgsn, false);
}
static int config_write_sgsn(struct vty *vty)
{
struct gbproxy_sgsn *sgsn;
llist_for_each_entry(sgsn, &g_cfg->sgsns, list)
write_sgsn(vty, sgsn);
return CMD_SUCCESS;
}
DEFUN(cfg_sgsn_nsei,
cfg_sgsn_nsei_cmd,
"sgsn nsei <0-65534>",
"Configure the SGSN\n"
"NSEI to be used in the connection with the SGSN\n"
"The NSEI\n")
{
uint32_t features = 0; // FIXME: make configurable
unsigned int nsei = atoi(argv[0]);
unsigned int num_sgsn = llist_count(&g_cfg->sgsns);
struct gbproxy_sgsn *sgsn;
struct gbproxy_nse *nse;
struct gbproxy_bvc *bvc;
if (num_sgsn >= GBPROXY_MAX_NR_SGSN) {
vty_out(vty, "%% Too many SGSN NSE defined (%d), increase GBPROXY_MAX_NR_SGSN%s",
num_sgsn, VTY_NEWLINE);
return CMD_WARNING;
}
/* This will have created the gbproxy_nse as well */
sgsn = gbproxy_sgsn_by_nsei_or_new(g_cfg, nsei);
if (!sgsn)
goto free_nothing;
nse = sgsn->nse;
if (num_sgsn > 1 && g_cfg->pool.nri_bitlen == 0)
vty_out(vty, "%% Multiple SGSNs defined, but no pooling enabled%s", VTY_NEWLINE);
if (!gbproxy_bvc_by_bvci(nse, 0)) {
uint8_t cause = BSSGP_CAUSE_OML_INTERV;
bvc = gbproxy_bvc_alloc(nse, 0);
if (!bvc)
goto free_sgsn;
bvc->fi = bssgp_bvc_fsm_alloc_sig_bss(bvc, nse->cfg->nsi, nsei, features);
if (!bvc->fi)
goto free_bvc;
bssgp_bvc_fsm_set_ops(bvc->fi, &sgsn_sig_bvc_fsm_ops, bvc);
osmo_fsm_inst_dispatch(bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);
}
vty->node = SGSN_NODE;
vty->index = sgsn;
return CMD_SUCCESS;
free_bvc:
gbproxy_bvc_free(bvc);
free_sgsn:
gbproxy_sgsn_free(sgsn);
free_nothing:
vty_out(vty, "%% Unable to create NSE for NSEI=%05u%s", nsei, VTY_NEWLINE);
return CMD_WARNING;
}
DEFUN(cfg_sgsn_name,
cfg_sgsn_name_cmd,
"name NAME",
"Configure the SGSN\n"
"Name the SGSN\n"
"The name\n")
{
struct gbproxy_sgsn *sgsn = vty->index;
const char *name = argv[0];
osmo_talloc_replace_string(sgsn, &sgsn->name, name);
if (!sgsn->name) {
vty_out(vty, "%% Unable to set name for SGSN with nsei %05u%s", sgsn->nse->nsei, VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN_ATTR(cfg_sgsn_nri_add, cfg_sgsn_nri_add_cmd,
"nri add <0-32767> [<0-32767>]",
NRI_STR "Add NRI value or range to the NRI mapping for this MSC\n"
NRI_FIRST_LAST_STR,
CMD_ATTR_IMMEDIATE)
{
struct gbproxy_sgsn *sgsn = vty->index;
struct gbproxy_sgsn *other_sgsn;
bool before;
int rc;
const char *message;
struct osmo_nri_range add_range;
rc = osmo_nri_ranges_vty_add(&message, &add_range, sgsn->pool.nri_ranges, argc, argv, g_cfg->pool.nri_bitlen);
if (message) {
NRI_WARN(sgsn, "%s: " NRI_ARGS_TO_STR_FMT, message, NRI_ARGS_TO_STR_ARGS(argc, argv));
}
if (rc < 0)
return CMD_WARNING;
/* Issue a warning about NRI range overlaps (but still allow them).
* Overlapping ranges will map to whichever SGSN comes fist in the gbproxy_config->sgsns llist,
* which should be the first one defined in the config */
before = true;
llist_for_each_entry(other_sgsn, &g_cfg->sgsns, list) {
if (other_sgsn == sgsn) {
before = false;
continue;
}
if (osmo_nri_range_overlaps_ranges(&add_range, other_sgsn->pool.nri_ranges)) {
uint16_t nsei = sgsn->nse->nsei;
uint16_t other_nsei = other_sgsn->nse->nsei;
NRI_WARN(sgsn, "NRI range [%d..%d] overlaps between NSE %05d and NSE %05d."
" For overlaps, NSE %05d has higher priority than NSE %05d",
add_range.first, add_range.last, nsei, other_nsei,
before ? other_nsei : nsei, before ? nsei : other_nsei);
}
}
return CMD_SUCCESS;
}
DEFUN_ATTR(cfg_sgsn_nri_del, cfg_sgsn_nri_del_cmd,
"nri del <0-32767> [<0-32767>]",
NRI_STR "Remove NRI value or range from the NRI mapping for this MSC\n"
NRI_FIRST_LAST_STR,
CMD_ATTR_IMMEDIATE)
{
struct gbproxy_sgsn *sgsn = vty->index;
int rc;
const char *message;
rc = osmo_nri_ranges_vty_del(&message, NULL, sgsn->pool.nri_ranges, argc, argv);
if (message) {
NRI_WARN(sgsn, "%s: " NRI_ARGS_TO_STR_FMT, message, NRI_ARGS_TO_STR_ARGS(argc, argv));
}
if (rc < 0)
return CMD_WARNING;
return CMD_SUCCESS;
}
DEFUN_ATTR(cfg_sgsn_allow_attach, cfg_sgsn_allow_attach_cmd,
"allow-attach",
"Allow this SGSN to attach new subscribers (default).\n",
CMD_ATTR_IMMEDIATE)
{
struct gbproxy_sgsn *sgsn = vty->index;
sgsn->pool.allow_attach = true;
return CMD_SUCCESS;
}
DEFUN_ATTR(cfg_sgsn_no_allow_attach, cfg_sgsn_no_allow_attach_cmd,
"no allow-attach",
NO_STR
"Do not assign new subscribers to this MSC."
" Useful if an MSC in an MSC pool is configured to off-load subscribers."
" The MSC will still be operational for already IMSI-Attached subscribers,"
" but the NAS node selection function will skip this MSC for new subscribers\n",
CMD_ATTR_IMMEDIATE)
{
struct gbproxy_sgsn *sgsn = vty->index;
sgsn->pool.allow_attach = false;
return CMD_SUCCESS;
}
DEFUN(sgsn_show_nri_all, show_nri_all_cmd,
"show nri all",
SHOW_STR NRI_STR "Show all SGSNs\n")
{
struct gbproxy_sgsn *sgsn;
llist_for_each_entry(sgsn, &g_cfg->sgsns, list)
sgsn_write_nri(vty, sgsn, true);
return CMD_SUCCESS;
}
DEFUN(show_nri_nsei, show_nri_nsei_cmd,
"show nri nsei <0-65535>",
SHOW_STR NRI_STR "Identify SGSN by NSEI\n"
"NSEI of the SGSN\n")
{
struct gbproxy_sgsn *sgsn;
int nsei = atoi(argv[0]);
sgsn = gbproxy_sgsn_by_nsei(g_cfg, nsei);
if (!sgsn) {
vty_out(vty, "%% No SGSN with found for NSEI %05d%s", nsei, VTY_NEWLINE);
return CMD_SUCCESS;
}
sgsn_write_nri(vty, sgsn, true);
return CMD_SUCCESS;
}
DEFUN(cfg_pool_bvc_fc_ratio,
cfg_pool_bvc_fc_ratio_cmd,
"pool bvc-flow-control-ratio <1-100>",
"SGSN Pool related configuration\n"
"Ratio of BSS-advertised bucket size + leak rate advertised to each SGSN\n"
"Ratio of BSS-advertised bucket size + leak rate advertised to each SGSN (Percent)\n")
{
g_cfg->pool.bvc_fc_ratio = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN_ATTR(cfg_gbproxy_nri_bitlen,
cfg_gbproxy_nri_bitlen_cmd,
"nri bitlen <0-15>",
NRI_STR
"Set number of bits that an NRI has, to extract from TMSI identities (always starting just after the TMSI's most significant octet).\n"
"bit count (0 disables) pooling)\n",
CMD_ATTR_IMMEDIATE)
{
g_cfg->pool.nri_bitlen = atoi(argv[0]);
if (llist_count(&g_cfg->sgsns) > 1 && g_cfg->pool.nri_bitlen == 0)
vty_out(vty, "%% Pooling disabled, but multiple SGSNs defined%s", VTY_NEWLINE);
/* TODO: Verify all nri ranges and warn on mismatch */
return CMD_SUCCESS;
}
DEFUN_ATTR(cfg_gbproxy_nri_null_add,
cfg_gbproxy_nri_null_add_cmd,
"nri null add <0-32767> [<0-32767>]",
NRI_STR NULL_NRI_STR "Add NULL-NRI value (or range)\n"
NRI_FIRST_LAST_STR,
CMD_ATTR_IMMEDIATE)
{
int rc;
const char *message;
rc = osmo_nri_ranges_vty_add(&message, NULL, g_cfg->pool.null_nri_ranges, argc, argv,
g_cfg->pool.nri_bitlen);
if (message) {
vty_out(vty, "%% nri null add: %s: " NRI_ARGS_TO_STR_FMT "%s", message, NRI_ARGS_TO_STR_ARGS(argc, argv),
VTY_NEWLINE);
vty_out(vty, "%s: \n" NRI_ARGS_TO_STR_FMT, message, NRI_ARGS_TO_STR_ARGS(argc, argv));
}
if (rc < 0)
return CMD_WARNING;
return CMD_SUCCESS;
}
DEFUN_ATTR(cfg_gbproxy_nri_null_del,
cfg_gbproxy_nri_null_del_cmd,
"nri null del <0-32767> [<0-32767>]",
NRI_STR NULL_NRI_STR "Remove NRI value or range from the NRI mapping for this MSC\n"
NRI_FIRST_LAST_STR,
CMD_ATTR_IMMEDIATE)
{
int rc;
const char *message;
rc = osmo_nri_ranges_vty_del(&message, NULL, g_cfg->pool.null_nri_ranges, argc, argv);
if (message) {
vty_out(vty, "%% %s: " NRI_ARGS_TO_STR_FMT "%s", message, NRI_ARGS_TO_STR_ARGS(argc, argv),
VTY_NEWLINE);
}
if (rc < 0)
return CMD_WARNING;
return CMD_SUCCESS;
}
static void log_set_bvc_filter(struct log_target *target,
const uint16_t *bvci)
{
if (bvci) {
uintptr_t bvci_filter = *bvci | BVC_LOG_CTX_FLAG;
target->filter_map |= (1 << LOG_FLT_GB_BVC);
target->filter_data[LOG_FLT_GB_BVC] = (void *)bvci_filter;
} else if (target->filter_data[LOG_FLT_GB_BVC]) {
target->filter_map = ~(1 << LOG_FLT_GB_BVC);
target->filter_data[LOG_FLT_GB_BVC] = NULL;
}
}
DEFUN(logging_fltr_bvc,
logging_fltr_bvc_cmd,
"logging filter bvc bvci <0-65535>",
LOGGING_STR FILTER_STR
"Filter based on BSSGP VC\n"
"Identify BVC by BVCI\n"
"Numeric identifier\n")
{
struct log_target *tgt;
uint16_t id = atoi(argv[0]);
log_tgt_mutex_lock();
tgt = osmo_log_vty2tgt(vty);
if (!tgt) {
log_tgt_mutex_unlock();
return CMD_WARNING;
}
log_set_bvc_filter(tgt, &id);
log_tgt_mutex_unlock();
return CMD_SUCCESS;
}
DEFUN(show_gbproxy_bvc, show_gbproxy_bvc_cmd, "show gbproxy bvc (bss|sgsn) [stats]",
SHOW_STR GBPROXY_STR
"Show BSSGP Virtual Connections\n"
"Display BSS-side BVCs\n"
"Display SGSN-side BVCs\n"
"Show statistics\n")
{
struct gbproxy_nse *nse;
bool show_stats = argc >= 2;
int i;
if (show_stats)
vty_out_rate_ctr_group(vty, "", g_cfg->ctrg);
if (!strcmp(argv[0], "bss")) {
hash_for_each(g_cfg->bss_nses, i, nse, list)
gbproxy_vty_print_nse(vty, nse, show_stats);
} else {
hash_for_each(g_cfg->sgsn_nses, i, nse, list)
gbproxy_vty_print_nse(vty, nse, show_stats);
}
return CMD_SUCCESS;
}
DEFUN(show_gbproxy_cell, show_gbproxy_cell_cmd, "show gbproxy cell [stats]",
SHOW_STR GBPROXY_STR
"Show GPRS Cell Information\n"
"Show statistics\n")
{
struct gbproxy_cell *cell;
bool show_stats = argc >= 1;
int i;
hash_for_each(g_cfg->cells, i, cell, list)
gbproxy_vty_print_cell(vty, cell, show_stats);
return CMD_SUCCESS;
}
DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",
SHOW_STR GBPROXY_STR "Show logical links\n")
{
struct gbproxy_nse *nse;
int i, j;
hash_for_each(g_cfg->bss_nses, i, nse, list) {
struct gbproxy_bvc *bvc;
hash_for_each(nse->bvcs, j, bvc, list) {
gbprox_vty_print_bvc(vty, bvc);
}
}
return CMD_SUCCESS;
}
DEFUN(show_gbproxy_tlli_cache, show_gbproxy_tlli_cache_cmd,
"show gbproxy tlli-cache",
SHOW_STR GBPROXY_STR "Show TLLI cache entries\n")
{
struct gbproxy_tlli_cache_entry *entry;
struct timespec now;
time_t expiry;
int i, count = 0;
osmo_clock_gettime(CLOCK_MONOTONIC, &now);
expiry = now.tv_sec - g_cfg->tlli_cache.timeout;
vty_out(vty, "TLLI cache timeout %us%s", g_cfg->tlli_cache.timeout, VTY_NEWLINE);
hash_for_each(g_cfg->tlli_cache.entries, i, entry, list) {
time_t valid = entry->tstamp - expiry;
struct gbproxy_nse *nse = entry->nse;
vty_out(vty, " TLLI %08x -> NSE(%05u/%s) valid %lds%s", entry->tlli, nse->nsei,
nse->sgsn_facing ? "SGSN" : "BSS", valid, VTY_NEWLINE);
count++;
}
vty_out(vty, "TLLI cache contains %u entries%s", count, VTY_NEWLINE);
return CMD_SUCCESS;
}
DEFUN(show_gbproxy_imsi_cache, show_gbproxy_imsi_cache_cmd,
"show gbproxy imsi-cache",
SHOW_STR GBPROXY_STR "Show IMSI cache entries\n")
{
struct gbproxy_imsi_cache_entry *entry;
struct timespec now;
time_t expiry;
int i, count = 0;
osmo_clock_gettime(CLOCK_MONOTONIC, &now);
expiry = now.tv_sec - g_cfg->imsi_cache.timeout;
vty_out(vty, "IMSI cache timeout %us%s", g_cfg->imsi_cache.timeout, VTY_NEWLINE);
hash_for_each(g_cfg->imsi_cache.entries, i, entry, list) {
time_t valid = entry->tstamp - expiry;
struct gbproxy_nse *nse = entry->nse;
vty_out(vty, " IMSI %s -> NSE(%05u/%s): valid %lds%s", entry->imsi, nse->nsei,
nse->sgsn_facing ? "SGSN" : "BSS", valid, VTY_NEWLINE);
count++;
}
vty_out(vty, "IMSI cache contains %u entries%s", count, VTY_NEWLINE);
return CMD_SUCCESS;
}
DEFUN(delete_gb_bvci, delete_gb_bvci_cmd,
"delete-gbproxy-peer <0-65534> bvci <2-65534>",
"Delete a GBProxy bvc by NSEI and optionally BVCI\n"
"NSEI number\n"
"Only delete bvc with a matching BVCI\n"
"BVCI number\n")
{
const uint16_t nsei = atoi(argv[0]);
const uint16_t bvci = atoi(argv[1]);
struct gbproxy_nse *nse = gbproxy_nse_by_nsei(g_cfg, nsei, NSE_F_BSS);
int counter;
if (!nse) {
vty_out(vty, "NSE not found%s", VTY_NEWLINE);
return CMD_WARNING;
}
counter = gbproxy_cleanup_bvcs(nse, bvci);
if (counter == 0) {
vty_out(vty, "BVC not found%s", VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
"delete-gbproxy-peer <0-65534> (only-bvc|only-nsvc|all) [dry-run]",
"Delete a GBProxy bvc by NSEI and optionally BVCI\n"
"NSEI number\n"
"Only delete BSSGP connections (BVC)\n"
"Only delete dynamic NS connections (NS-VC)\n"
"Delete BVC and dynamic NS connections\n"
"Show what would be deleted instead of actually deleting\n"
)
{
const uint16_t nsei = atoi(argv[0]);
const char *mode = argv[1];
int dry_run = argc > 2;
int delete_bvc = 0;
int delete_nsvc = 0;
int counter;
if (strcmp(mode, "only-bvc") == 0)
delete_bvc = 1;
else if (strcmp(mode, "only-nsvc") == 0)
delete_nsvc = 1;
else
delete_bvc = delete_nsvc = 1;
if (delete_bvc) {
if (!dry_run) {
struct gbproxy_nse *nse = gbproxy_nse_by_nsei(g_cfg, nsei, NSE_F_BSS);
counter = gbproxy_cleanup_bvcs(nse, 0);
gbproxy_nse_free(nse);
} else {
struct gbproxy_nse *nse;
struct gbproxy_bvc *bvc;
int i, j;
counter = 0;
hash_for_each(g_cfg->bss_nses, i, nse, list) {
if (nse->nsei != nsei)
continue;
hash_for_each(nse->bvcs, j, bvc, list) {
vty_out(vty, "BVC: ");
gbprox_vty_print_bvc(vty, bvc);
counter += 1;
}
}
}
vty_out(vty, "%sDeleted %d BVC%s",
dry_run ? "Not " : "", counter, VTY_NEWLINE);
}
if (delete_nsvc) {
struct gprs_ns2_inst *nsi = g_cfg->nsi;
struct gprs_ns2_nse *nse;
nse = gprs_ns2_nse_by_nsei(nsi, nsei);
if (!nse) {
vty_out(vty, "NSEI not found%s", VTY_NEWLINE);
return CMD_WARNING;
}
/* TODO: We should NOT delete a persistent NSEI/NSVC as soon as we can check for these */
if (!dry_run)
gprs_ns2_free_nse(nse);
vty_out(vty, "%sDeleted NS-VCs for NSEI %d%s",
dry_run ? "Not " : "", nsei, VTY_NEWLINE);
}
return CMD_SUCCESS;
}
/* Only for ttcn3 testing */
DEFUN_HIDDEN(sgsn_pool_nsf_fixed, sgsn_pool_nsf_fixed_cmd,
"sgsn-pool nsf fixed NAME",
"SGSN pooling: load balancing across multiple SGSNs.\n"
"Customize the Network Selection Function.\n"
"Set a fixed SGSN to use (for testing).\n"
"The name of the SGSN to use.\n")
{
const char *name = argv[0];
struct gbproxy_sgsn *sgsn = gbproxy_sgsn_by_name(g_cfg, name);
if (!sgsn) {
vty_out(vty, "%% Could not find SGSN with name %s%s", name, VTY_NEWLINE);
return CMD_WARNING;
}
g_cfg->pool.nsf_override = sgsn;
return CMD_SUCCESS;
}
DEFUN_HIDDEN(sgsn_pool_nsf_normal, sgsn_pool_nsf_normal_cmd,
"sgsn-pool nsf normal",
"SGSN pooling: load balancing across multiple SGSNs.\n"
"Customize the Network Selection Function.\n"
"Reset the NSF back to regular operation (for testing).\n")
{
g_cfg->pool.nsf_override = NULL;
return CMD_SUCCESS;
}
int gbproxy_vty_init(void)
{
install_element_ve(&show_gbproxy_bvc_cmd);
install_element_ve(&show_gbproxy_cell_cmd);
install_element_ve(&show_gbproxy_links_cmd);
install_element_ve(&show_gbproxy_tlli_cache_cmd);
install_element_ve(&show_gbproxy_imsi_cache_cmd);
install_element_ve(&show_nri_all_cmd);
install_element_ve(&show_nri_nsei_cmd);
install_element_ve(&logging_fltr_bvc_cmd);
install_element(ENABLE_NODE, &delete_gb_bvci_cmd);
install_element(ENABLE_NODE, &delete_gb_nsei_cmd);
install_element(ENABLE_NODE, &sgsn_pool_nsf_fixed_cmd);
install_element(ENABLE_NODE, &sgsn_pool_nsf_normal_cmd);
install_element(CONFIG_NODE, &cfg_gbproxy_cmd);
install_node(&gbproxy_node, config_write_gbproxy);
install_element(GBPROXY_NODE, &cfg_pool_bvc_fc_ratio_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_nri_bitlen_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_nri_null_add_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_nri_null_del_cmd);
install_element(CONFIG_NODE, &cfg_sgsn_nsei_cmd);
install_node(&sgsn_node, config_write_sgsn);
install_element(SGSN_NODE, &cfg_sgsn_name_cmd);
install_element(SGSN_NODE, &cfg_sgsn_allow_attach_cmd);
install_element(SGSN_NODE, &cfg_sgsn_no_allow_attach_cmd);
install_element(SGSN_NODE, &cfg_sgsn_nri_add_cmd);
install_element(SGSN_NODE, &cfg_sgsn_nri_del_cmd);
return 0;
}
int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg)
{
int rc;
g_cfg = cfg;
rc = vty_read_config_file(config_file, NULL);
if (rc < 0) {
fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
return rc;
}
return 0;
}

View File

@ -33,8 +33,6 @@ EXTRA_DIST = \
vty_test_runner.py \
ctrl_test_runner.py \
osmo-sgsn_test-nodes.vty \
osmo-gbproxy_test-nodes.vty \
osmo-gbproxy-pool_test-nodes.vty \
$(NULL)
TESTSUITE = $(srcdir)/testsuite
@ -62,14 +60,6 @@ vty-python-test: $(BUILT_SOURCES)
# pass -u to vty_script_runner.py by doing:
# make vty-transcript-test U=-u
vty-transcript-test:
osmo_verify_transcript_vty.py -v \
-n OsmoGbProxy -p 4246 \
-r "$(top_builddir)/src/gbproxy/osmo-gbproxy -c $(top_srcdir)/doc/examples/osmo-gbproxy/osmo-gbproxy.cfg" \
$(U) $${T:-$(srcdir)/osmo-gbproxy_test-nodes.vty}
osmo_verify_transcript_vty.py -v \
-n OsmoGbProxy -p 4246 \
-r "$(top_builddir)/src/gbproxy/osmo-gbproxy -c $(top_srcdir)/doc/examples/osmo-gbproxy/osmo-gbproxy-pool.cfg" \
$(U) $${T:-$(srcdir)/osmo-gbproxy-pool_test-nodes.vty}
osmo_verify_transcript_vty.py -v \
-n OsmoSGSN -p 4245 \
-r "$(top_builddir)/src/sgsn/osmo-sgsn -c $(top_srcdir)/doc/examples/osmo-sgsn/osmo-sgsn.cfg" \

View File

@ -1,35 +0,0 @@
OsmoGbProxy> enable
OsmoGbProxy# show nri all
sgsn nsei 101
nri add 1
nri add 11
sgsn nsei 102
nri add 2
nri add 12
OsmoGbProxy# configure terminal
OsmoGbProxy(config)# list
...
gbproxy
sgsn nsei <0-65534>
ns
...
OsmoGbProxy(config)# sgsn nsei 101
OsmoGbProxy(config-sgsn)# list
...
allow-attach
no allow-attach
nri add <0-32767> [<0-32767>]
nri del <0-32767> [<0-32767>]
...
OsmoGbProxy(config-sgsn)# exit
OsmoGbProxy(config)# gbproxy
OsmoGbProxy(config-gbproxy)# list
...
pool bvc-flow-control-ratio <1-100>
nri bitlen <0-15>
nri null add <0-32767> [<0-32767>]
nri null del <0-32767> [<0-32767>]
...

View File

@ -1,32 +0,0 @@
OsmoGbProxy> enable
OsmoGbProxy# show nri all
sgsn nsei 101
% no NRI mappings
...
OsmoGbProxy# configure terminal
OsmoGbProxy(config)# list
...
gbproxy
sgsn nsei <0-65534>
ns
...
OsmoGbProxy(config)# sgsn nsei 101
OsmoGbProxy(config-sgsn)# list
...
allow-attach
no allow-attach
nri add <0-32767> [<0-32767>]
nri del <0-32767> [<0-32767>]
...
OsmoGbProxy(config-sgsn)# exit
OsmoGbProxy(config)# gbproxy
OsmoGbProxy(config-gbproxy)# list
...
pool bvc-flow-control-ratio <1-100>
nri bitlen <0-15>
nri null add <0-32767> [<0-32767>]
nri null del <0-32767> [<0-32767>]
...

View File

@ -67,53 +67,6 @@ class TestVTYBase(unittest.TestCase):
self.vty = None
osmoutil.end_proc(self.proc)
class TestVTYGbproxy(TestVTYBase):
def vty_command(self):
return ["./src/gbproxy/osmo-gbproxy", "-c",
"doc/examples/osmo-gbproxy/osmo-gbproxy.cfg"]
def vty_app(self):
return (4246, "./src/gbproxy/osmo-gbproxy", "OsmoGbProxy", "gbproxy")
def testVtyTree(self):
self.vty.enable()
self.assertTrue(self.vty.verify('configure terminal', ['']))
self.assertEqual(self.vty.node(), 'config')
self.checkForEndAndExit()
self.assertTrue(self.vty.verify('ns', ['']))
self.assertEqual(self.vty.node(), 'config-ns')
self.checkForEndAndExit()
self.assertTrue(self.vty.verify('exit', ['']))
self.assertEqual(self.vty.node(), 'config')
self.assertTrue(self.vty.verify('gbproxy', ['']))
self.assertEqual(self.vty.node(), 'config-gbproxy')
self.checkForEndAndExit()
self.assertTrue(self.vty.verify('exit', ['']))
self.assertEqual(self.vty.node(), 'config')
def testVtyShow(self):
res = self.vty.command("show ns")
self.assertTrue(res.find('UDP bind') >= 0)
res = self.vty.command("show gbproxy bvc bss stats")
self.assertTrue(res.find('GBProxy Global Statistics') >= 0)
def testVtyDeletePeer(self):
self.vty.enable()
self.assertTrue(self.vty.verify('delete-gbproxy-peer 9999 bvci 7777', ['NSE not found']))
res = self.vty.command("delete-gbproxy-peer 9999 all dry-run")
self.assertTrue(res.find('Not Deleted 0 BVC') >= 0)
self.assertTrue(res.find('NSEI not found') >= 0)
res = self.vty.command("delete-gbproxy-peer 9999 only-bvc dry-run")
self.assertTrue(res.find('Not Deleted 0 BVC') >= 0)
res = self.vty.command("delete-gbproxy-peer 9999 only-nsvc dry-run")
self.assertTrue(res.find('NSEI not found') >= 0)
res = self.vty.command("delete-gbproxy-peer 9999 all")
self.assertTrue(res.find('Deleted 0 BVC') >= 0)
self.assertTrue(res.find('NSEI not found') >= 0)
class TestVTYSGSN(TestVTYBase):
def vty_command(self):
@ -274,13 +227,6 @@ class TestVTYSGSN(TestVTYBase):
for t in [3312, 3322, 3350, 3360, 3370, 3313, 3314, 3316, 3385, 3395, 3397]:
self.assertTrue(self.vty.verify('timer t%d 10' % t, ['']))
def add_gbproxy_test(suite, workdir):
if not os.path.isfile(os.path.join(workdir, "src/gbproxy/osmo-gbproxy")):
print("Skipping the Gb-Proxy test")
return
test = unittest.TestLoader().loadTestsFromTestCase(TestVTYGbproxy)
suite.addTest(test)
def add_sgsn_test(suite, workdir):
if not os.path.isfile(os.path.join(workdir, "src/sgsn/osmo-sgsn")):
print("Skipping the SGSN test")
@ -318,7 +264,6 @@ if __name__ == '__main__':
os.chdir(workdir)
print("Running tests for specific VTY commands")
suite = unittest.TestSuite()
add_gbproxy_test(suite, workdir)
add_sgsn_test(suite, workdir)
if args.test_name: