Follow up the DNS-based SGW/PGW selection introduced by #4693 and harden several fallback, asynchronous completion, cache, resolver, and compatibility paths found during review and testing. A DNS failure must never prevent an attach when a statically configured gateway remains available. Preserve the SGW serving the UE when a DNS resolution is created and restore it whenever a later DNS-based SGW selection cannot complete. This is required because a previous Create Session Request attempt may already have switched the UE to a DNS-discovered SGW. If that request times out and the next DNS candidate cannot be resolved, simply returning from apply_sgw() leaves the UE attached to the failed DNS SGW and causes subsequent CSR attempts to continue using it instead of the original fallback SGW. Restore the pre-DNS SGW when: * the SGW DNS leg ends in fallback after an earlier SGW switch * mme_sgw_add() cannot create the selected SGW node * ogs_gtp_connect() cannot connect the selected SGW * the deferred Create Session Request cannot be built or committed The fallback pointer records the SGW currently serving the UE when the resolution is created rather than assuming it is always statically configured. Successfully connected SGW nodes are retained for the process lifetime, so the stored pointer remains valid. The PGW path does not require the same state restoration. When PGW DNS selection falls back, mme_dns_sess_pgw_addr() returns NULL and the S11 Create Session Request builder selects the statically configured PGW again on each attempt. Harden deferred CSR completion handling. post_resolved() runs on the MME main thread, which is also responsible for draining the application event queue. ogs_queue_push() can block indefinitely when that queue is full, causing a self-deadlock because the blocked producer is also the only consumer. Use ogs_queue_trypush() instead. When it returns OGS_RETRY, return the resolution to PENDING and restart its guard timer. The DNS legs are already complete, so the guard callback simply attempts to post the completed result again. Do not retry when the queue has been terminated during shutdown. Do not move a resolution to CONSUMED or increment csr_attempts until the deferred CSR transaction has been successfully built and committed. The GTP timeout retry path uses CONSUMED as its eligibility condition, so marking an unsent request as consumed leaves meaningless retry state. If local CSR creation fails, restore the pre-DNS SGW first and then remove the resolution. This prevents a subsequent NAS retry from capturing the failed DNS SGW as its new fallback and prevents a stale CONSUMED resolution from incorrectly short-circuiting the new request to SEND_NOW. Document that OGS_OK from mme_gtp_send_create_session_request() may mean that the request was deferred for DNS selection and does not guarantee that a GTP transaction exists when the function returns. Fix an MME event-loop hang caused by unusable SRV answers. An SRV record whose target is "." indicates that the service is not available. mme_dns_candidate_apply_srv() previously left the candidate unchanged in this case. leg_advance() then repeatedly read the same cached SRV answer without advancing the candidate cursor, hanging the MME event loop. Make mme_dns_candidate_apply_srv() return whether it found a usable target. Skip the candidate when all SRV targets are empty or ".", while leaving the candidate unchanged for callers that need to inspect the failure. Add unit and DNS integration coverage for this case. Extend the test DNS server to encode "." as the DNS root label and verify that the MME skips the unusable SRV candidate and falls back instead of hanging. Bound the MME DNS cache to prevent expired entries from accumulating indefinitely across many TAC and APN names. When inserting a new key at capacity: * remove expired entries * if the cache remains full, evict entries closest to expiry * do not make room when replacing an existing key, which would otherwise evict an unrelated entry on every refresh at capacity Disable the c-ares internal query cache when the installed c-ares version provides ARES_OPT_QUERY_CACHE. c-ares 1.31 and later enable an internal cache by default, which can continue answering a query after the MME's own cache entry has expired and silently override the operator-configured dns.cache_ttl. Set qcache_max_ttl to zero so the MME cache remains authoritative. Retain compatibility with both older distribution versions of c-ares and newer releases that deprecate the legacy query and reply parsing APIs. Define CARES_NO_DEPRECATED before including ares.h to suppress the newer deprecation attributes without raising the minimum supported c-ares version. Validate configured resolver addresses before initializing c-ares. Require each dns.server address to be a bare IPv4 or IPv6 literal. Reject hostnames, malformed addresses, bracketed addresses, scope suffixes, and IPv6 link-local addresses, which require interface scope handling that is not supported by the MME configuration. Format resolver entries as: * IPv4: address:port * IPv6: [address]:port The brackets are required by the c-ares server CSV format. Without them, a value such as 2001:db8::53:53 is accepted as a different valid IPv6 address using the default DNS port, causing queries to be sent silently to the wrong resolver. Build and validate the server CSV before c-ares initialization so configuration failures do not require partially initialized channel or library cleanup. The fixed CSV buffer remains safe because inet_pton() guarantees that accepted addresses fit the maximum IPv4 or IPv6 literal length. Explicitly initialize mme_sess_t::dns_id to OGS_INVALID_POOL_ID instead of relying on the current value of the pool allocator's zero-filled memory. Update the sample configuration and documentation to describe the current DNS-selection limitations: * roaming PGW lookup currently builds the APN-FQDN from the serving PLMN rather than deriving the home-PLMN APN-OI * only A records are used for discovered gateways * SRV weights are ignored * non-terminal NAPTR records are not followed * DNS-discovered SGW nodes are retained for the process lifetime * resolver addresses must be bare IPv4 or IPv6 literals * link-local IPv6 resolvers are not supported Add the c-ares development dependency to Debian, Ubuntu, Fedora, Alpine, CentOS, macOS, and FreeBSD build instructions and container images, and add the c-ares MIT license notice. Also link the DNS selection unit tests against libmme directly so they exercise the same mme-dns-select implementation built for the MME.
2.8 KiB
| title | head_inline |
|---|---|
| Alpine | <style> .blue { color: blue; } </style> |
This guide is based on Alpine 3.13 Distribution. {: .blue}
Getting MongoDB
Tip: MongoDB is used as the database for PCF/UDR and PCRF/HSS. {: .notice--info}
Note: If you use an external MongoDB server, you can skip this section. {: .notice--warning}
Install MongoDB with package manager.
$ sudo apk update
$ sudo apk add mongodb
Run MongoDB server.
$ mkdir -p ./data/db
$ mongod --dbpath ./data/db
Setting up TUN device (No persistent after rebooting)
Create the TUN device. Interface name will be ogstun.
$ sudo apk add iproute2
$ sudo ip tuntap add name ogstun mode tun
$ ip link show
You are now ready to set the IP address on TUN device.
$ sudo ip addr add 10.45.0.1/16 dev ogstun
$ sudo ip addr add 2001:db8:cafe::1/48 dev ogstun
Make sure it is set up properly.
$ sudo ip link set ogstun up
$ ip link show
Tip: The script provided in [$GIT_REPO/misc/netconf.sh](https://github.com/{{ site.github_username }}/open5gs/blob/main/misc/netconf.sh) makes it easy to configure the TUN device as follows:
$ sudo ./misc/netconf.sh
{: .notice--info}
Building Open5GS
Install the depedencies for building the source code.
$ sudo apk add alpine-sdk bison flex git cmake meson bash sudo linux-headers bsd-compat-headers yaml-dev lksctp-tools-dev gnutls-dev libgcrypt-dev libidn-dev c-ares-dev mongo-c-driver-dev libmicrohttpd-dev curl-dev nghttp2-dev talloc-dev
Git clone.
$ git clone https://github.com/{{ site.github_username }}/open5gs
To compile with meson:
$ cd open5gs
$ meson build --prefix=`pwd`/install
$ ninja -C build
Check whether the compilation is correct.
$ ./build/tests/attach/attach ## EPC Only
$ ./build/tests/registration/registration ## 5G Core Only
Run all test programs as below.
$ cd build
$ meson test -v
Tip: You can also check the result of ninja -C build test with a tool that captures packets. If you are running wireshark, select the loopback interface and set FILTER to s1ap || gtpv2 || pfcp || diameter || gtp || ngap || http2.data.data || http2.headers. You can see the virtually created packets. [testattach.pcapng]({{ site.url }}{{ site.baseurl }}/assets/pcapng/testattach.pcapng)/[testregistration.pcapng]({{ site.url }}{{ site.baseurl }}/assets/pcapng/testregistration.pcapng)
{: .notice--info}
You need to perform the installation process.
$ cd build
$ ninja install
$ cd ../
Building WebUI of Open5GS
Node.js is required to build WebUI of Open5GS
$ sudo apk add nodejs
Install the dependencies to run WebUI
$ cd webui
$ npm ci
The WebUI runs as an npm script.
$ npm run dev