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:
parent
4be5ab3707
commit
901ed14c89
|
@ -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
|
||||
|
||||
|
|
|
@ -259,7 +259,6 @@ AC_OUTPUT(
|
|||
src/Makefile
|
||||
src/gprs/Makefile
|
||||
src/sgsn/Makefile
|
||||
src/gbproxy/Makefile
|
||||
src/gtphub/Makefile
|
||||
tests/Makefile
|
||||
tests/atlocal
|
||||
|
|
|
@ -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"
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
:
|
|
@ -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
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
@ -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).
|
|
@ -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"];
|
||||
}
|
||||
----
|
|
@ -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.
|
|
@ -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.
|
|
@ -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.
|
|
@ -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>
|
|
@ -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[]
|
|
@ -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>
|
||||
|
|
@ -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" \
|
||||
|
|
|
@ -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
|
@ -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 \
|
||||
|
|
|
@ -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
|
|
@ -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]
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
SUBDIRS = \
|
||||
gprs \
|
||||
sgsn \
|
||||
gbproxy \
|
||||
gtphub \
|
||||
$(NULL)
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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" \
|
||||
|
|
|
@ -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>]
|
||||
...
|
|
@ -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>]
|
||||
...
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue