Projects
osmocom:latest
osmo-ggsn
Sign Up
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 4
View file
osmo-ggsn.spec
Changed
@@ -18,22 +18,23 @@ Name: osmo-ggsn Requires: osmocom-latest -Version: 1.9.0 +Version: 1.10.0 Release: 0 Summary: GPRS Support Node License: GPL-2.0-only AND LGPL-2.1-or-later Group: Productivity/Telephony/Servers URL: https://osmocom.org/projects/openggsn -Source: osmo-ggsn_1.9.0.tar.xz +Source: osmo-ggsn_1.10.0.tar.xz +Source1: rpmlintrc BuildRequires: libtool >= 2 BuildRequires: pkgconfig >= 0.20 %if 0%{?suse_version} BuildRequires: systemd-rpm-macros %endif BuildRequires: pkgconfig(libgtpnl) >= 1.2.0 -BuildRequires: pkgconfig(libosmocore) >= 1.7.0 -BuildRequires: pkgconfig(libosmoctrl) >= 1.7.0 -BuildRequires: pkgconfig(libosmovty) >= 1.7.0 +BuildRequires: pkgconfig(libosmocore) >= 1.8.0 +BuildRequires: pkgconfig(libosmoctrl) >= 1.8.0 +BuildRequires: pkgconfig(libosmovty) >= 1.8.0 Obsoletes: openggsn %{?systemd_requires} @@ -75,7 +76,7 @@ and GTPCv2. %prep -%setup -q +%setup -n osmo-ggsn -q %build echo "%{version}" >.tarball-version
View file
osmo-ggsn_1.9.0.dsc -> osmo-ggsn_1.10.0.dsc
Changed
@@ -2,13 +2,13 @@ Source: osmo-ggsn Binary: osmo-ggsn, libgtp6, gtp-echo-responder, libgtp-dev, osmo-ggsn-dbg, gtp-echo-responder-dbg, libgtp-dbg, osmo-ggsn-doc Architecture: any all -Version: 1.9.0 +Version: 1.10.0 Maintainer: Osmocom team <openbsc@lists.osmocom.org> Homepage: https://projects.osmocom.org/projects/openggsn Standards-Version: 3.9.6 Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn -Build-Depends: debhelper (>= 9), autotools-dev, pkg-config, libdpkg-perl, git, dh-autoreconf, libosmocore-dev (>= 1.7.0), osmo-gsm-manuals-dev, libgtpnl-dev (>= 1.2.0) +Build-Depends: debhelper (>= 9), autotools-dev, pkg-config, libdpkg-perl, git, dh-autoreconf, libosmocore-dev (>= 1.8.0), osmo-gsm-manuals-dev, libgtpnl-dev (>= 1.2.0) Package-List: gtp-echo-responder deb net optional arch=any gtp-echo-responder-dbg deb debug extra arch=any @@ -19,8 +19,8 @@ osmo-ggsn-dbg deb debug extra arch=any osmo-ggsn-doc deb doc optional arch=all Checksums-Sha1: - b73aefe02d31c3d6026fad5f916b5e123b0daff8 186540 osmo-ggsn_1.9.0.tar.xz + ef7379362700b953612c879153008382955e76fa 192048 osmo-ggsn_1.10.0.tar.xz Checksums-Sha256: - 560bf8eab21a097f04ddcf55f2517ca82e6a9e1ce66b428c1263736ce52d705d 186540 osmo-ggsn_1.9.0.tar.xz + aaa208bd32e799fec506ca36d16bbd0214bf624f0d21edf75e211aee5e872aea 192048 osmo-ggsn_1.10.0.tar.xz Files: - 86b26dbafd0c12798d954fddc7775e94 186540 osmo-ggsn_1.9.0.tar.xz + 1f9c13039fbe53b038846d414889fad3 192048 osmo-ggsn_1.10.0.tar.xz
View file
osmo-ggsn_1.9.0.tar.xz/.tarball-version -> osmo-ggsn_1.10.0.tar.xz/.tarball-version
Changed
@@ -1 +1 @@ -1.9.0 \ No newline at end of file +1.10.0
View file
osmo-ggsn_1.9.0.tar.xz/configure.ac -> osmo-ggsn_1.10.0.tar.xz/configure.ac
Changed
@@ -154,9 +154,9 @@ AM_INIT_AUTOMAKE(foreign) -PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.7.0) -PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.7.0) -PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.7.0) +PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.8.0) +PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.8.0) +PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.8.0) AC_ARG_ENABLE(sanitize, AS_HELP_STRING(
View file
osmo-ggsn_1.9.0.tar.xz/contrib/osmo-ggsn.spec.in -> osmo-ggsn_1.10.0.tar.xz/contrib/osmo-ggsn.spec.in
Changed
@@ -17,6 +17,7 @@ %define _lto_cflags %{nil} Name: osmo-ggsn +Requires: osmocom-latest Version: @VERSION@ Release: 0 Summary: GPRS Support Node @@ -30,9 +31,9 @@ BuildRequires: systemd-rpm-macros %endif BuildRequires: pkgconfig(libgtpnl) >= 1.2.0 -BuildRequires: pkgconfig(libosmocore) >= 1.7.0 -BuildRequires: pkgconfig(libosmoctrl) >= 1.7.0 -BuildRequires: pkgconfig(libosmovty) >= 1.7.0 +BuildRequires: pkgconfig(libosmocore) >= 1.8.0 +BuildRequires: pkgconfig(libosmoctrl) >= 1.8.0 +BuildRequires: pkgconfig(libosmovty) >= 1.8.0 Obsoletes: openggsn %{?systemd_requires} @@ -42,6 +43,7 @@ such as GPRS, EDGE, UMTS or HSPA. %package -n libgtp6 +Requires: osmocom-latest Summary: Library implementing GTP between SGSN and GGSN License: GPL-2.0-only Group: System/Libraries @@ -50,6 +52,7 @@ libgtp implements the GPRS Tunneling Protocol between SGSN and GGSN. %package -n libgtp-devel +Requires: osmocom-latest Summary: Development files for the GTP library License: GPL-2.0-only Group: Development/Libraries/C and C++ @@ -62,6 +65,7 @@ applications that want to make use of libgtp. %package -n gtp-echo-responder +Requires: osmocom-latest Summary: Small program answering GTP ECHO Request with GTP ECHO Response License: MIT Group: System/Libraries
View file
osmo-ggsn_1.9.0.tar.xz/contrib/systemd/osmo-ggsn.service -> osmo-ggsn_1.10.0.tar.xz/contrib/systemd/osmo-ggsn.service
Changed
@@ -5,6 +5,8 @@ Service Type=simple Restart=always +StateDirectory=osmocom +WorkingDirectory=%S/osmocom ExecStart=/usr/bin/osmo-ggsn -c /etc/osmocom/osmo-ggsn.cfg RestartSec=2 RestartPreventExitStatus=1
View file
osmo-ggsn_1.9.0.tar.xz/debian/changelog -> osmo-ggsn_1.10.0.tar.xz/debian/changelog
Changed
@@ -1,3 +1,23 @@ +osmo-ggsn (1.10.0) unstable; urgency=medium + + Max + * Set working directory in systemd service file + * Ignore .deb build byproducts + * ctrl: take both address and port from vty config + + Pau Espin Pedrol + * cosmetic: gtp: Fix typo in comment + * Split gsn_t related APIs out of gtp.{c,h} + * Use rate_ctr for gsn_t available_counters + * ggsn: Introduce tdef and make it configurable over VTY + * gtp: Introduce VTY configurable GTP timer X3 + * Fix typos in comments and VTY descriptions + + arehbein + * osmo-ggsn: Transition to use of 'telnet_init_default' + + -- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 07 Feb 2023 14:29:48 +0100 + osmo-ggsn (1.9.0) unstable; urgency=medium Pau Espin Pedrol
View file
osmo-ggsn_1.9.0.tar.xz/debian/control -> osmo-ggsn_1.10.0.tar.xz/debian/control
Changed
@@ -7,7 +7,7 @@ pkg-config, libdpkg-perl, git, dh-autoreconf, - libosmocore-dev (>= 1.7.0), + libosmocore-dev (>= 1.8.0), osmo-gsm-manuals-dev, libgtpnl-dev (>= 1.2.0) Standards-Version: 3.9.6
View file
osmo-ggsn_1.9.0.tar.xz/ggsn/ggsn.h -> osmo-ggsn_1.10.0.tar.xz/ggsn/ggsn.h
Changed
@@ -6,6 +6,7 @@ #include <osmocom/core/linuxlist.h> #include <osmocom/core/select.h> #include <osmocom/core/timer.h> +#include <osmocom/core/tdef.h> #include <osmocom/ctrl/control_if.h> #include "../lib/tun.h" @@ -65,9 +66,9 @@ uint32_t apn_type_mask; /* GTP-U via TUN device or in Linux kernel */ enum apn_gtpu_mode gtpu_mode; - /* administratively shut-down (true) or not (false) */ + /* administratively shut down (true) or not (false) */ bool shutdown; - /* transmit G-PDU sequeence numbers (true) or not (false) */ + /* transmit G-PDU sequence numbers (true) or not (false) */ bool tx_gpdu_seq; } cfg; @@ -127,7 +128,7 @@ char *state_dir; /* Time between Echo requests on each SGSN */ unsigned int echo_interval; - /* administratively shut-down (true) or not (false) */ + /* administratively shut down (true) or not (false) */ bool shutdown; } cfg; @@ -152,6 +153,7 @@ /* ggsn_main.c */ extern struct ctrl_handle *g_ctrlh; extern void *tall_ggsn_ctx; +extern struct osmo_tdef_group ggsn_tdef_group; /* ggsn.c */ extern int ggsn_start(struct ggsn_ctx *ggsn);
View file
osmo-ggsn_1.9.0.tar.xz/ggsn/ggsn_main.c -> osmo-ggsn_1.10.0.tar.xz/ggsn/ggsn_main.c
Changed
@@ -34,6 +34,7 @@ #include <osmocom/core/stats.h> #include <osmocom/core/rate_ctr.h> #include <osmocom/core/timer.h> +#include <osmocom/core/tdef.h> #include <osmocom/core/utils.h> #include <osmocom/ctrl/control_if.h> #include <osmocom/ctrl/control_cmd.h> @@ -60,6 +61,11 @@ static char *config_file = "osmo-ggsn.cfg"; +struct osmo_tdef_group ggsn_tdef_group = { + {.name = "gtp", .tdefs = gtp_T_defs, .desc = "GTP (libgtp) timers" }, + { } +}; + /* To exit gracefully. Used with GCC compilation flag -pg and gprof */ static void signal_handler(int s) { @@ -217,12 +223,11 @@ exit(2); } - rc = telnet_init_dynif(tall_ggsn_ctx, NULL, vty_get_bind_addr(), OSMO_VTY_PORT_GGSN); + rc = telnet_init_default(tall_ggsn_ctx, NULL, OSMO_VTY_PORT_GGSN); if (rc < 0) exit(1); - g_ctrlh = ctrl_interface_setup_dynip(NULL, ctrl_vty_get_bind_addr(), - OSMO_CTRL_PORT_GGSN, NULL); + g_ctrlh = ctrl_interface_setup(NULL, OSMO_CTRL_PORT_GGSN, NULL); if (!g_ctrlh) { LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n"); exit(1);
View file
osmo-ggsn_1.9.0.tar.xz/ggsn/ggsn_vty.c -> osmo-ggsn_1.10.0.tar.xz/ggsn/ggsn_vty.c
Changed
@@ -33,6 +33,7 @@ #include <osmocom/vty/command.h> #include <osmocom/vty/vty.h> #include <osmocom/vty/misc.h> +#include <osmocom/vty/tdef_vty.h> #include "../gtp/gtp.h" #include "../gtp/pdp.h" @@ -298,7 +299,7 @@ DEFUN(cfg_ggsn_shutdown, cfg_ggsn_shutdown_cmd, "shutdown ggsn", - "Put the GGSN in administrative shut-down\n" GGSN_STR) + "Put the GGSN in administrative shutdown\n" GGSN_STR) { struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index; @@ -315,7 +316,7 @@ DEFUN(cfg_ggsn_no_shutdown, cfg_ggsn_no_shutdown_cmd, "no shutdown ggsn", - NO_STR GGSN_STR "Remove the GGSN from administrative shut-down\n") + NO_STR GGSN_STR "Remove the GGSN from administrative shutdown\n") { struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index; @@ -343,7 +344,7 @@ DEFUN(cfg_ggsn_show_sgsn, cfg_ggsn_show_sgsn_cmd, "show sgsn", - NO_STR GGSN_STR "Remove the GGSN from administrative shut-down\n") + NO_STR GGSN_STR "Remove the GGSN from administrative shutdown\n") { struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index; struct sgsn_peer *sgsn; @@ -680,7 +681,7 @@ DEFUN(cfg_apn_shutdown, cfg_apn_shutdown_cmd, "shutdown", - "Put the APN in administrative shut-down\n") + "Put the APN in administrative shutdown\n") { struct apn_ctx *apn = (struct apn_ctx *) vty->index; @@ -697,7 +698,7 @@ DEFUN(cfg_apn_no_shutdown, cfg_apn_no_shutdown_cmd, "no shutdown", - NO_STR "Remove the APN from administrative shut-down\n") + NO_STR "Remove the APN from administrative shutdown\n") { struct apn_ctx *apn = (struct apn_ctx *) vty->index; @@ -795,6 +796,7 @@ vty_out(vty, " gtp control-ip %s%s", in46a_ntoa(&ggsn->cfg.gtpc_addr), VTY_NEWLINE); if (ggsn->cfg.gtpu_addr.v4.s_addr) vty_out(vty, " gtp user-ip %s%s", in46a_ntoa(&ggsn->cfg.gtpu_addr), VTY_NEWLINE); + osmo_tdef_vty_groups_write(vty, " "); llist_for_each_entry(apn, &ggsn->apn_list, list) config_write_apn(vty, apn); if (ggsn->cfg.default_apn) @@ -1113,6 +1115,8 @@ install_element(GGSN_NODE, &cfg_ggsn_echo_interval_cmd); install_element(GGSN_NODE, &cfg_ggsn_no_echo_interval_cmd); + osmo_tdef_vty_groups_init(GGSN_NODE, ggsn_tdef_group); + install_node(&apn_node, NULL); install_element(APN_NODE, &cfg_description_cmd); install_element(APN_NODE, &cfg_no_description_cmd);
View file
osmo-ggsn_1.9.0.tar.xz/gtp/Makefile.am -> osmo-ggsn_1.10.0.tar.xz/gtp/Makefile.am
Changed
@@ -2,14 +2,14 @@ # Please read chapter "Library interface versions" of the libtool documentation # before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html # If major=current-age is increased, remember to update the dh_strip line in debian/rules! -LIBVERSION=8:1:2 +LIBVERSION=9:0:3 lib_LTLIBRARIES = libgtp.la -include_HEADERS = gtp.h pdp.h gtpie.h +include_HEADERS = gtp.h gsn.h pdp.h gtpie.h AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS) -libgtp_la_SOURCES = gtp.c gtp.h gtpie.c gtpie.h pdp.c pdp.h lookupa.c lookupa.h queue.c queue.h +libgtp_la_SOURCES = gtp.c gtp.h gsn.c gsn.h gtpie.c gtpie.h pdp.c pdp.h lookupa.c lookupa.h queue.c queue.h libgtp_la_LDFLAGS = -version-info $(LIBVERSION) -no-undefined libgtp_la_LIBADD = $(LIBOSMOCORE_LIBS)
View file
osmo-ggsn_1.10.0.tar.xz/gtp/gsn.c
Added
@@ -0,0 +1,596 @@ +/* + * OsmoGGSN - Gateway GPRS Support Node + * Copyright (C) 2002, 2003, 2004 Mondru AB. + * Copyright (C) 2010-2011, 2016-2017 Harald Welte <laforge@gnumonks.org> + * Copyright (C) 2015-2017 sysmocom - s.f.m.c. GmbH + * + * The contents of this file may be used under the terms of the GNU + * General Public License Version 2, provided that the above copyright + * notice and this permission notice is included in all copies or + * substantial portions of the software. + * + */ + +/* + * gtp.c: Contains all GTP functionality. Should be able to handle multiple + * tunnels in the same program. + * + * TODO: + * - Do we need to handle fragmentation? + */ + +#ifdef __linux__ +#define _GNU_SOURCE 1 +#endif + +#include <osmocom/core/logging.h> +#include <osmocom/core/utils.h> +#include <osmocom/core/stats.h> +#include <osmocom/core/rate_ctr.h> + +#if defined(__FreeBSD__) +#include <sys/endian.h> +#endif + +#include "../config.h" +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/stat.h> +#include <time.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> + +#include <arpa/inet.h> + +/* #include <stdint.h> ISO C99 types */ + +#include "pdp.h" +#include "gtp.h" +#include "gtpie.h" +#include "queue.h" + +/* Error reporting functions */ + +#define LOGP_WITH_ADDR(ss, level, addr, fmt, args...) \ + LOGP(ss, level, "addr(%s:%d) " fmt, \ + inet_ntoa((addr).sin_addr), htons((addr).sin_port), \ + ##args); + +static const struct rate_ctr_desc gsn_ctr_description = { + GSN_CTR_ERR_SOCKET = { "err:socket", "Socket error" }, + GSN_CTR_ERR_READFROM = { "err:readfrom", "readfrom() errors" }, + GSN_CTR_ERR_SENDTO = { "err:sendto", "sendto() errors" }, + GSN_CTR_ERR_QUEUEFULL = { "err:queuefull", "Failed to queue message because queue is full" }, + GSN_CTR_ERR_SEQ = { "err:seq", "Sequence number out of range" }, + GSN_CTR_ERR_ADDRESS = { "err:address", "GSN address conversion failed" }, + GSN_CTR_ERR_UNKNOWN_PDP = { "err:unknown_pdp", "Failed looking up PDP context" }, + GSN_CTR_ERR_UNEXPECTED_CAUSE = { "err:unexpected_cause", "Unexpected cause value received" }, + GSN_CTR_ERR_OUT_OF_PDP = { "err:out_of_pdp", "Out of storage for PDP contexts" }, + GSN_CTR_PKT_EMPTY = { "pkt:empty", "Empty packet received" }, + GSN_CTR_PKT_UNSUP = { "pkt:unsupported", "Unsupported GTP version received" }, + GSN_CTR_PKT_TOOSHORT = { "pkt:too_short", "Packet too short received" }, + GSN_CTR_PKT_UNKNOWN = { "pkt:unknown", "Unknown packet type received" }, + GSN_CTR_PKT_UNEXPECT = { "pkt:unexpected", "Unexpected packet type received" }, + GSN_CTR_PKT_DUPLICATE = { "pkt:duplicate", "Duplicate or unsolicited packet received" }, + GSN_CTR_PKT_MISSING = { "pkt:missing", "Missing IE in packet received" }, + GSN_CTR_PKT_INCORRECT = { "pkt:incorrect", "Incorrect IE in packet received" }, + GSN_CTR_PKT_INVALID = { "pkt:invalid", "Invalid format in packet received" }, +}; + +static const struct rate_ctr_group_desc gsn_ctrg_desc = { + "gsn", + "GSN Statistics", + OSMO_STATS_CLASS_PEER, + ARRAY_SIZE(gsn_ctr_description), + gsn_ctr_description, +}; +static unsigned int gsn_ctr_next_idx = 0; + +/* Global timer definitions for GTP operation, provided for convenience. To make these user configurable, it is convenient to add + * gtp_gsn_tdefs as one of your program's osmo_tdef_group entries and call osmo_tdef_vty_init(). */ +struct osmo_tdef gtp_T_defs = { + { .T = GTP_GSN_TIMER_T3_RESPONSE, .default_val = 5, .unit = OSMO_TDEF_S, + .desc = "Timer T3-RESPONSE holds the maximum wait time for a response of a request message" + }, + { .T = GTP_GSN_TIMER_N3_REQUESTS, .default_val = 3, .unit = OSMO_TDEF_CUSTOM, + .desc = "Counter N3-REQUESTS holds the maximum number of attempts made by GTP to send a request message" + }, + { .T = GTP_GSN_TIMER_T3_HOLD_RESPONSE, .default_val = 5 * 3 /* (GTP_GSN_TIMER_T3_RESPONSE * GTP_GSN_TIMER_N3_REQUESTS) */, .unit = OSMO_TDEF_S, + .desc = "Time a GTP respoonse message is kept cached to re-transmit it when a duplicate request is received. Value is generally equal to (T3-RESPONSE * N3-REQUESTS) set at the peer" + }, + {} +}; + + +/* API Functions */ + +/* Deprecated, use gtp_pdp_newpdp() instead */ +int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, + uint64_t imsi, uint8_t nsapi) +{ + int rc; + rc = gtp_pdp_newpdp(gsn, pdp, imsi, nsapi, NULL); + return rc; +} + +int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp) +{ + if (gsn->cb_delete_context) + gsn->cb_delete_context(pdp); + return pdp_freepdp(pdp); +} + +/* Free pdp and all its secondary PDP contexts. Must be called on the primary PDP context. */ +int gtp_freepdp_teardown(struct gsn_t *gsn, struct pdp_t *pdp) +{ + int n; + struct pdp_t *secondary_pdp; + OSMO_ASSERT(!pdp->secondary); + + for (n = 0; n < PDP_MAXNSAPI; n++) { + if (pdp->secondary_tein) { + if (gtp_pdp_getgtp1(gsn, &secondary_pdp, + pdp->secondary_tein)) { + LOGP(DLGTP, LOGL_ERROR, + "Unknown secondary PDP context\n"); + continue; + } + if (pdp != secondary_pdp) { + gtp_freepdp(gsn, secondary_pdp); + } + } + } + + return gtp_freepdp(gsn, pdp); +} + +/* gtp_gpdu */ + +extern int gtp_fd(struct gsn_t *gsn) +{ + return gsn->fd0; +} + +int gtp_set_cb_unsup_ind(struct gsn_t *gsn, + int (*cb) (struct sockaddr_in * peer)) +{ + gsn->cb_unsup_ind = cb; + return 0; +} + +int gtp_set_cb_extheader_ind(struct gsn_t *gsn, + int (*cb) (struct sockaddr_in * peer)) +{ + gsn->cb_extheader_ind = cb; + return 0; +} + +int gtp_set_cb_ran_info_relay_ind(struct gsn_t *gsn, + int (*cb) (struct sockaddr_in * peer, union gtpie_member **ie)) +{ + gsn->cb_ran_info_relay_ind = cb; + return 0; +} + +/* API: Initialise delete context callback */ +/* Called whenever a pdp context is deleted for any reason */ +int gtp_set_cb_delete_context(struct gsn_t *gsn, int (*cb) (struct pdp_t * pdp)) +{ + gsn->cb_delete_context = cb; + return 0; +} + +int gtp_set_cb_conf(struct gsn_t *gsn, + int (*cb) (int type, int cause, + struct pdp_t * pdp, void *cbp)) +{
View file
osmo-ggsn_1.10.0.tar.xz/gtp/gsn.h
Added
@@ -0,0 +1,181 @@ +/* + * OsmoGGSN - Gateway GPRS Support Node + * Copyright (C) 2002, 2003, 2004 Mondru AB. + * + * The contents of this file may be used under the terms of the GNU + * General Public License Version 2, provided that the above copyright + * notice and this permission notice is included in all copies or + * substantial portions of the software. + * + */ + +#ifndef _GSN_H +#define _GSN_H + +#include <osmocom/core/utils.h> +#include <osmocom/core/defs.h> +#include <osmocom/core/timer.h> +#include <osmocom/core/tdef.h> +#include <osmocom/core/rate_ctr.h> + +#include "pdp.h" + +#define GTP_MODE_GGSN 1 +#define GTP_MODE_SGSN 2 + +#define RESTART_FILE "gsn_restart" + +extern struct osmo_tdef gtp_T_defs; + +/* *********************************************************** + * Information storage for each gsn instance + * + * Normally each instance of the application corresponds to + * one instance of a gsn. + * + * In order to avoid global variables in the application, and + * also in order to allow several instances of a gsn in the same + * application this struct is provided in order to store all + * relevant information related to the gsn. + * + * Note that this does not include information storage for ' + * each pdp context. This is stored in another struct. + *************************************************************/ + +enum gsn_rate_ctr_keys { + GSN_CTR_ERR_SOCKET, + GSN_CTR_ERR_READFROM, /* Number of readfrom errors */ + GSN_CTR_ERR_SENDTO, /* Number of sendto errors */ + GSN_CTR_ERR_QUEUEFULL, /* Number of times queue was full */ + GSN_CTR_ERR_SEQ, /* Number of seq out of range */ + GSN_CTR_ERR_ADDRESS, /* GSN address conversion failed */ + GSN_CTR_ERR_UNKNOWN_PDP, /* GSN address conversion failed */ + GSN_CTR_ERR_UNEXPECTED_CAUSE, /* Unexpected cause value received */ + GSN_CTR_ERR_OUT_OF_PDP, /* Out of storage for PDP contexts */ + GSN_CTR_PKT_EMPTY, /* Number of empty packets */ + GSN_CTR_PKT_UNSUP, /* Number of unsupported version 29.60 11.1.1 */ + GSN_CTR_PKT_TOOSHORT, /* Number of too short headers 29.60 11.1.2 */ + GSN_CTR_PKT_UNKNOWN, /* Number of unknown messages 29.60 11.1.3 */ + GSN_CTR_PKT_UNEXPECT, /* Number of unexpected messages 29.60 11.1.4 */ + GSN_CTR_PKT_DUPLICATE, /* Number of duplicate or unsolicited replies */ + GSN_CTR_PKT_MISSING, /* Number of missing information field messages */ + GSN_CTR_PKT_INCORRECT, /* Number of incorrect information field messages */ + GSN_CTR_PKT_INVALID, /* Number of invalid message format messages */ +}; + +/* 3GPP TS 29.006 14.1, 14,2 */ +enum gtp_gsn_timers { + GTP_GSN_TIMER_T3_RESPONSE = 3, + GTP_GSN_TIMER_N3_REQUESTS = 1003, + GTP_GSN_TIMER_T3_HOLD_RESPONSE = -3, +}; + +struct gsn_t { + /* Parameters related to the network interface */ + + int fd0; /* GTP0 file descriptor */ + int fd1c; /* GTP1 control plane file descriptor */ + int fd1u; /* GTP0 user plane file descriptor */ + int mode; /* Mode of operation: GGSN or SGSN */ + struct in_addr gsnc; /* IP address of this gsn for signalling */ + struct in_addr gsnu; /* IP address of this gsn for user traffic */ + + /* Parameters related to signalling messages */ + uint16_t seq_next; /* Next sequence number to use */ + int seq_first; /* First packet in queue (oldest timeout) */ + int seq_last; /* Last packet in queue (youngest timeout) */ + + unsigned char restart_counter; /* Increment on restart. Stored on disk */ + char *statedir; /* Disk location for permanent storage */ + void *priv; /* used by libgtp users to attach their own state) */ + struct queue_t *queue_req; /* Request queue */ + struct queue_t *queue_resp; /* Response queue */ + + struct pdp_t pdpaPDP_MAX; /* PDP storage */ + struct pdp_t *hashtidPDP_MAX; /* Hash table for IMSI + NSAPI */ + + struct osmo_timer_list queue_timer; /* internal queue_{req,resp} timer */ + + /* Call back functions */ + int (*cb_delete_context) (struct pdp_t *); + int (*cb_create_context_ind) (struct pdp_t *); + int (*cb_unsup_ind) (struct sockaddr_in * peer); + int (*cb_extheader_ind) (struct sockaddr_in * peer); + int (*cb_ran_info_relay_ind) (struct sockaddr_in *peer, union gtpie_member **ie); + int (*cb_conf) (int type, int cause, struct pdp_t * pdp, void *cbp); + int (*cb_data_ind) (struct pdp_t * pdp, void *pack, unsigned len); + int (*cb_recovery) (struct sockaddr_in * peer, uint8_t recovery); + int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery); + int (*cb_recovery3) (struct gsn_t *gsn, struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery); + + /* Counters */ + struct rate_ctr_group *ctrg; + + /* Timers: */ + struct osmo_tdef *tdef; +}; + +/* External API functions */ + +extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, + int mode); + +extern int gtp_free(struct gsn_t *gsn); + +extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, + uint64_t imsi, uint8_t nsapi) OSMO_DEPRECATED("Use gtp_pdp_newpdp() instead"); +extern int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp); +extern int gtp_freepdp_teardown(struct gsn_t *gsn, struct pdp_t *pdp); + +extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp, + void *cbp); + +extern int gtp_set_cb_create_context_ind(struct gsn_t *gsn, + int (*cb_create_context_ind) (struct + pdp_t * + pdp)); +extern int gtp_set_cb_data_ind(struct gsn_t *gsn, + int (*cb_data_ind) (struct pdp_t * pdp, + void *pack, unsigned len)); +extern int gtp_set_cb_delete_context(struct gsn_t *gsn, + int (*cb_delete_context) (struct pdp_t * + pdp)); +/*extern int gtp_set_cb_create_context(struct gsn_t *gsn, + int (*cb_create_context) (struct pdp_t* pdp)); */ + +extern int gtp_set_cb_unsup_ind(struct gsn_t *gsn, + int (*cb) (struct sockaddr_in * peer)); + +extern int gtp_set_cb_extheader_ind(struct gsn_t *gsn, + int (*cb) (struct sockaddr_in * peer)); + +extern int gtp_set_cb_ran_info_relay_ind(struct gsn_t *gsn, + int (*cb) (struct sockaddr_in * peer, union gtpie_member **ie)); + +extern int gtp_set_cb_conf(struct gsn_t *gsn, + int (*cb) (int type, int cause, struct pdp_t * pdp, + void *cbp)); + +int gtp_set_cb_recovery(struct gsn_t *gsn, + int (*cb) (struct sockaddr_in * peer, + uint8_t recovery)) + OSMO_DEPRECATED("Use gtp_set_cb_recovery2() instead, to obtain pdp ctx originating the recovery"); +int gtp_set_cb_recovery2(struct gsn_t *gsn, + int (*cb) (struct sockaddr_in * peer, + struct pdp_t * pdp, + uint8_t recovery)) + OSMO_DEPRECATED("Use gtp_set_cb_recovery3() instead, to obtain gsn handling the recovery"); +int gtp_set_cb_recovery3(struct gsn_t *gsn, + int (*cb) (struct gsn_t * gsn, struct sockaddr_in * peer, + struct pdp_t * pdp, + uint8_t recovery)); +void gtp_clear_queues(struct gsn_t *gsn); +extern int gtp_fd(struct gsn_t *gsn); + +extern int gtp_retrans(struct gsn_t *gsn) OSMO_DEPRECATED("This API is a no-op, libgtp already does the job internally"); +extern int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) OSMO_DEPRECATED("This API is a no-op and will return a 1 day timeout"); + +/* Internal APIs: */ +void gtp_queue_timer_start(struct gsn_t *gsn); + +#endif /* !_GSN_H */
View file
osmo-ggsn_1.9.0.tar.xz/gtp/gtp.c -> osmo-ggsn_1.10.0.tar.xz/gtp/gtp.c
Changed
@@ -60,11 +60,6 @@ #include "gtpie.h" #include "queue.h" -/* According to section 14.2 of 3GPP TS 29.006 version 6.9.0 */ -#define N3_REQUESTS 5 - -#define T3_REQUEST 3 - /* Error reporting functions */ #define GTP_LOGPKG(pri, peer, pack, len, fmt, args...) \ @@ -131,93 +126,7 @@ { 0, NULL } }; -/* Deprecated, use gtp_pdp_newpdp() instead */ -int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, - uint64_t imsi, uint8_t nsapi) -{ - int rc; - rc = gtp_pdp_newpdp(gsn, pdp, imsi, nsapi, NULL); - return rc; -} - -int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp) -{ - if (gsn->cb_delete_context) - gsn->cb_delete_context(pdp); - return pdp_freepdp(pdp); -} - -/* Free pdp and all its secondary PDP contexts. Must be called on the primary PDP context. */ -int gtp_freepdp_teardown(struct gsn_t *gsn, struct pdp_t *pdp) -{ - int n; - struct pdp_t *secondary_pdp; - OSMO_ASSERT(!pdp->secondary); - - for (n = 0; n < PDP_MAXNSAPI; n++) { - if (pdp->secondary_tein) { - if (gtp_pdp_getgtp1(gsn, &secondary_pdp, - pdp->secondary_tein)) { - LOGP(DLGTP, LOGL_ERROR, - "Unknown secondary PDP context\n"); - continue; - } - if (pdp != secondary_pdp) { - gtp_freepdp(gsn, secondary_pdp); - } - } - } - - return gtp_freepdp(gsn, pdp); -} - -/* gtp_gpdu */ - -extern int gtp_fd(struct gsn_t *gsn) -{ - return gsn->fd0; -} - -/* gtp_decaps */ -/* gtp_retrans */ -/* gtp_retranstimeout */ - -int gtp_set_cb_unsup_ind(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in * peer)) -{ - gsn->cb_unsup_ind = cb; - return 0; -} - -int gtp_set_cb_extheader_ind(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in * peer)) -{ - gsn->cb_extheader_ind = cb; - return 0; -} - -int gtp_set_cb_ran_info_relay_ind(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in * peer, union gtpie_member **ie)) -{ - gsn->cb_ran_info_relay_ind = cb; - return 0; -} -/* API: Initialise delete context callback */ -/* Called whenever a pdp context is deleted for any reason */ -int gtp_set_cb_delete_context(struct gsn_t *gsn, int (*cb) (struct pdp_t * pdp)) -{ - gsn->cb_delete_context = cb; - return 0; -} - -int gtp_set_cb_conf(struct gsn_t *gsn, - int (*cb) (int type, int cause, - struct pdp_t * pdp, void *cbp)) -{ - gsn->cb_conf = cb; - return 0; -} static void emit_cb_recovery(struct gsn_t *gsn, struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery) @@ -230,50 +139,6 @@ gsn->cb_recovery3(gsn, peer, pdp, recovery); } -int gtp_set_cb_recovery(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in * peer, uint8_t recovery)) -{ - gsn->cb_recovery = cb; - return 0; -} - -/* cb_recovery() - * pdp may be NULL if Recovery IE was received from a message independent - * of any PDP ctx (such as Echo Response), or because pdp ctx is unknown to the - * local setup. In case pdp is known, caller may want to keep that pdp alive to - * handle subsequent msg cb as this specific pdp ctx is still valid according to - * specs. - */ -int gtp_set_cb_recovery2(struct gsn_t *gsn, - int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery)) -{ - gsn->cb_recovery2 = cb_recovery2; - return 0; -} - -/* cb_recovery() - * pdp may be NULL if Recovery IE was received from a message independent - * of any PDP ctx (such as Echo Response), or because pdp ctx is unknown to the - * local setup. In case pdp is known, caller may want to keep that pdp alive to - * handle subsequent msg cb as this specific pdp ctx is still valid according to - * specs. - */ -int gtp_set_cb_recovery3(struct gsn_t *gsn, - int (*cb_recovery3) (struct gsn_t *gsn, struct sockaddr_in *peer, - struct pdp_t *pdp, uint8_t recovery)) -{ - gsn->cb_recovery3 = cb_recovery3; - return 0; -} - -int gtp_set_cb_data_ind(struct gsn_t *gsn, - int (*cb_data_ind) (struct pdp_t * pdp, - void *pack, unsigned len)) -{ - gsn->cb_data_ind = cb_data_ind; - return 0; -} - /** * get_default_gtp() * Generate a GPRS Tunneling Protocol signalling packet header, depending @@ -393,108 +258,6 @@ } } -static int queue_timer_retrans(struct gsn_t *gsn) -{ - /* Retransmit any outstanding packets */ - /* Remove from queue if maxretrans exceeded */ - time_t now; - struct qmsg_t *qmsg; - now = time(NULL); - - /* get first element in queue, as long as the timeout of that - * element has expired */ - while ((!queue_getfirst(gsn->queue_req, &qmsg)) && - (qmsg->timeout <= now)) { - if (qmsg->retrans > N3_REQUESTS) { /* Too many retrans */ - LOGP(DLGTP, LOGL_NOTICE, "Retransmit req queue timeout of seq %" PRIu16 "\n", - qmsg->seq); - if (gsn->cb_conf) - gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp); - queue_freemsg(gsn->queue_req, qmsg); - } else { - LOGP(DLGTP, LOGL_INFO, "Retransmit (%d) of seq %" PRIu16 "\n", - qmsg->retrans, qmsg->seq); - if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0, - (struct sockaddr *)&qmsg->peer, - sizeof(struct sockaddr_in)) < 0) { - gsn->err_sendto++; - LOGP(DLGTP, LOGL_ERROR, - "Sendto(fd0=%d, msg=%lx, len=%d) failed: Error = %s\n", - gsn->fd0, (unsigned long)&qmsg->p, - qmsg->l, strerror(errno)); - } - queue_back(gsn->queue_req, qmsg); - qmsg->timeout = now + T3_REQUEST; - qmsg->retrans++; - } - } - - /* Also clean up reply timeouts */ - while ((!queue_getfirst(gsn->queue_resp, &qmsg)) && - (qmsg->timeout < now)) {
View file
osmo-ggsn_1.9.0.tar.xz/gtp/gtp.h -> osmo-ggsn_1.10.0.tar.xz/gtp/gtp.h
Changed
@@ -13,14 +13,10 @@ #define _GTP_H #include <osmocom/core/utils.h> -#include <osmocom/core/defs.h> -#include <osmocom/core/timer.h> #include "gtpie.h" #include "pdp.h" - -#define GTP_MODE_GGSN 1 -#define GTP_MODE_SGSN 2 +#include "gsn.h" #define GTP0_PORT 3386 #define GTP1C_PORT 2123 @@ -32,12 +28,10 @@ #define GTP1_HEADER_SIZE_SHORT 8 #define GTP1_HEADER_SIZE_LONG 12 +#define NAMESIZE 1024 #define SYSLOG_PRINTSIZE 255 #define ERRMSG_SIZE 255 -#define RESTART_FILE "gsn_restart" -#define NAMESIZE 1024 - /* GTP version 1 extension header type definitions. */ #define GTP_EXT_PDCP_PDU 0xC0 /* PDCP PDU Number */ @@ -232,105 +226,13 @@ struct gtp1_packet_long gtp1l; } __attribute__ ((packed)); -/* *********************************************************** - * Information storage for each gsn instance - * - * Normally each instance of the application corresponds to - * one instance of a gsn. - * - * In order to avoid global variables in the application, and - * also in order to allow several instances of a gsn in the same - * application this struct is provided in order to store all - * relevant information related to the gsn. - * - * Note that this does not include information storage for ' - * each pdp context. This is stored in another struct. - *************************************************************/ - -struct gsn_t { - /* Parameters related to the network interface */ - - int fd0; /* GTP0 file descriptor */ - int fd1c; /* GTP1 control plane file descriptor */ - int fd1u; /* GTP0 user plane file descriptor */ - int mode; /* Mode of operation: GGSN or SGSN */ - struct in_addr gsnc; /* IP address of this gsn for signalling */ - struct in_addr gsnu; /* IP address of this gsn for user traffic */ - - /* Parameters related to signalling messages */ - uint16_t seq_next; /* Next sequence number to use */ - int seq_first; /* First packet in queue (oldest timeout) */ - int seq_last; /* Last packet in queue (youngest timeout) */ - - unsigned char restart_counter; /* Increment on restart. Stored on disk */ - char *statedir; /* Disk location for permanent storage */ - void *priv; /* used by libgtp users to attach their own state) */ - struct queue_t *queue_req; /* Request queue */ - struct queue_t *queue_resp; /* Response queue */ - - struct pdp_t pdpaPDP_MAX; /* PDP storage */ - struct pdp_t *hashtidPDP_MAX; /* Hash table for IMSI + NSAPI */ - - struct osmo_timer_list queue_timer; /* internal queue_{req,resp} timer */ - - /* Call back functions */ - int (*cb_delete_context) (struct pdp_t *); - int (*cb_create_context_ind) (struct pdp_t *); - int (*cb_unsup_ind) (struct sockaddr_in * peer); - int (*cb_extheader_ind) (struct sockaddr_in * peer); - int (*cb_ran_info_relay_ind) (struct sockaddr_in *peer, union gtpie_member **ie); - int (*cb_conf) (int type, int cause, struct pdp_t * pdp, void *cbp); - int (*cb_data_ind) (struct pdp_t * pdp, void *pack, unsigned len); - int (*cb_recovery) (struct sockaddr_in * peer, uint8_t recovery); - int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery); - int (*cb_recovery3) (struct gsn_t *gsn, struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery); - - /* Counters */ - - uint64_t err_socket; /* Number of socket errors */ - uint64_t err_readfrom; /* Number of readfrom errors */ - uint64_t err_sendto; /* Number of sendto errors */ - uint64_t err_memcpy; /* Number of memcpy */ - uint64_t err_queuefull; /* Number of times queue was full */ - uint64_t err_seq; /* Number of seq out of range */ - uint64_t err_address; /* GSN address conversion failed */ - uint64_t err_unknownpdp; /* GSN address conversion failed */ - uint64_t err_unknowntid; /* Application supplied unknown imsi+nsapi */ - uint64_t err_cause; /* Unexpected cause value received */ - uint64_t err_outofpdp; /* Out of storage for PDP contexts */ - - uint64_t empty; /* Number of empty packets */ - uint64_t unsup; /* Number of unsupported version 29.60 11.1.1 */ - uint64_t tooshort; /* Number of too short headers 29.60 11.1.2 */ - uint64_t unknown; /* Number of unknown messages 29.60 11.1.3 */ - uint64_t unexpect; /* Number of unexpected messages 29.60 11.1.4 */ - uint64_t duplicate; /* Number of duplicate or unsolicited replies */ - uint64_t missing; /* Number of missing information field messages */ - uint64_t incorrect; /* Number of incorrect information field messages */ - uint64_t invalid; /* Number of invalid message format messages */ -}; - /* External API functions */ extern const char *gtp_version(); -extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, - int mode); - -extern int gtp_free(struct gsn_t *gsn); - -extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, - uint64_t imsi, uint8_t nsapi) OSMO_DEPRECATED("Use gtp_pdp_newpdp() instead"); -extern int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp); -extern int gtp_freepdp_teardown(struct gsn_t *gsn, struct pdp_t *pdp); extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp); -extern int gtp_set_cb_create_context_ind(struct gsn_t *gsn, - int (*cb_create_context_ind) (struct - pdp_t * - pdp)); - extern int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause); @@ -351,53 +253,10 @@ const uint8_t *rim_route_addr, size_t rim_route_addr_len, uint8_t rim_route_addr_discr); -extern int gtp_set_cb_data_ind(struct gsn_t *gsn, - int (*cb_data_ind) (struct pdp_t * pdp, - void *pack, unsigned len)); - -extern int gtp_fd(struct gsn_t *gsn); extern int gtp_decaps0(struct gsn_t *gsn); extern int gtp_decaps1c(struct gsn_t *gsn); extern int gtp_decaps1u(struct gsn_t *gsn); -extern int gtp_retrans(struct gsn_t *gsn) OSMO_DEPRECATED("This API is a no-op, libgtp already does the job internally"); -extern int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) OSMO_DEPRECATED("This API is a no-op and will return a 1 day timeout"); - -extern int gtp_set_cb_delete_context(struct gsn_t *gsn, - int (*cb_delete_context) (struct pdp_t * - pdp)); -/*extern int gtp_set_cb_create_context(struct gsn_t *gsn, - int (*cb_create_context) (struct pdp_t* pdp)); */ - -extern int gtp_set_cb_unsup_ind(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in * peer)); - -extern int gtp_set_cb_extheader_ind(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in * peer)); - -extern int gtp_set_cb_ran_info_relay_ind(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in * peer, union gtpie_member **ie)); - -extern int gtp_set_cb_conf(struct gsn_t *gsn, - int (*cb) (int type, int cause, struct pdp_t * pdp, - void *cbp)); - -int gtp_set_cb_recovery(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in * peer, - uint8_t recovery)) - OSMO_DEPRECATED("Use gtp_set_cb_recovery2() instead, to obtain pdp ctx originating the recovery"); -int gtp_set_cb_recovery2(struct gsn_t *gsn, - int (*cb) (struct sockaddr_in * peer, - struct pdp_t * pdp, - uint8_t recovery)) - OSMO_DEPRECATED("Use gtp_set_cb_recovery3() instead, to obtain gsn handling the recovery");; -int gtp_set_cb_recovery3(struct gsn_t *gsn, - int (*cb) (struct gsn_t * gsn, struct sockaddr_in * peer, - struct pdp_t * pdp, - uint8_t recovery)); - -void gtp_clear_queues(struct gsn_t *gsn); - -/* Internal functions (not part of the API */ +/* Internal functions (not part of the API) */ extern int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp, struct in_addr *inetaddrs);
View file
rpmlintrc
Added
@@ -0,0 +1,5 @@ +# Don't abort the build when finding a library that depends on a package with +# a specific version. This is intentional for nightly builds, we don't want +# libraries from different build dates to be mixed as they might have ABI +# incompatibilities. +setBadness('shlib-fixed-dependency', 0)
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.