== Running OsmoUPF

The OsmoUPF executable (`osmo-upf`) offers the following command-line
arguments:

=== SYNOPSIS

*osmo-upf* [-h|-V] [-D] [-c 'CONFIGFILE']

=== OPTIONS

*-h, --help*::
	Print a short help message about the supported options
*-V, --version*::
	Print the compile-time version number of the OsmoHNBGW program
*-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-upf.cfg` in the current
	working directory.

=== Multiple instances

Running multiple instances of `osmo-upf` on the same computer is possible if
all interfaces (VTY, CTRL, PFCP) are separated using the appropriate
configuration options. The IP based interfaces are binding to local host by
default. In order to separate the processes, the user has to bind those
services to different ports, or different specific IP addresses.

The VTY and the Control interface can be bound to IP addresses from the loopback
address range, for example:

----
line vty
 bind 127.0.0.2
ctrl
 bind 127.0.0.2
----

The PFCP port is specified to be fixed as port 8805. Hence, each osmo-upf
process needs to run on a distinct local interface:

----
pfcp
  local-addr 10.9.0.2
----

For GTP encapsulation/decapsulation and GTP tunnel relaying, osmo-upf depends on
the IP addresses configured at the Linux kernel GTP module, and the IP addresses
negotiated within PFCP by the control plane function.

If multiple `osmo-upf` processes are running on the same Linux kernel, each
`osmo-upf` needs to be configured with a distinct netfilter table name, so that
naming of individual tunnel rulesets does not collide:

----
tunmap
 table-name osmo-upf-2
----

=== Configure PFCP Server

The following example configures OsmoUPF to listen for PFCP association requests
from Control Plane Function entities on local interface 10.9.8.7, port 8805:

----
pfcp
 local-addr 10.9.8.7
----

3GPP TS 29.244 4.2.2 specifies that PFCP Request messages shall be sent to UDP
port 8805, i.e. the PFCP port is fixed as 8805 and currently not configurable in
osmo-upf.

Setting a 'local-addr' is required: the PFCP protocol features a Node ID, which
uniquely identifies PFCP peers across different interfaces. According to the
PFCP specification, the Node ID can be a fully-qualified domain name (FQDN) or
an IP address. Currently, osmo-upf has no support for using an FQDN as Node
ID, and so far uses the 'local-addr' as local Node ID -- hence the 'local-addr'
must not be "0.0.0.0", which is an unfortunate consequence. This is likely to
improve in the future, see https://osmocom.org/issues/5682 .

=== Linux Kernel Features

OsmoUPF uses two distinct Linux kernel features:

* The GTP module is used for `tunend`: GTP encapsulation/decapsulation from/to
  "the internet".

* The netfilter framework and nftables are used for `tunmap`: GTP tunnel proxying,
  also known as tunnel forwarding or tunnel mapping.

.Linux kernel feature usage
[graphviz]
----
include::upf_gtp_roles.dot[]
----

GTP kernel module configuration in the `tunend` section can be omitted for sites
that serve only as GTP forwarding proxy, without encapsulation/decapsulation of
GTP payloads -- except to provide GTP Echo service, see <<gtp_echo>>.

Netfilter configuration in the `tunmap` section can be omitted for sites only
serving as GTP tunnel endpoint.

[[gtp_module]]
=== Configure Linux Kernel GTP Module for `tunend`

The Linux kernel GTP module is used for the `tunend` use case, i.e. GTP
encapsulation/decapsulation from/to "the internet".

To use the GTP kernel module, OsmoUPF requires a GTP device, which is a
dedicated network device provided by the Linux kernel, serving as GTP tunnel
endpoint. It is typically named like "apn0".

`osmo-upf` can either create a GTP device on startup, or use a pre-existing GTP
device. To en/decapsulate GTP, the APN device needs to be assigned an IP address
range that matches the UE IP addresses that are configured in GTP-C / PFCP.

The following configuration placed in `osmo-upf.cfg` creates a GTP device called
`apn23` on startup of osmo-upf, which is destroyed on program exit. It listens
for GTP on local IP address `1.2.3.4`:

----
tunend
 dev create apn23 1.2.3.4
----

TODO:: `osmo-upf` is not yet able to configure this network device's IP address
range, MTU etc.

The following configuration placed in `osmo-upf.cfg` uses a pre-existing device
called `apn42`:

----
tunend
 dev use apn42 2.3.4.5
----

GTP kernel devices can be managed manually using the `gtp-link` program
available from the 'libgtpnl' project:

----
# gtp-link add apn42
(keep this process running)
# ip addr add dev apn42 192.168.42.1/24

$ osmo-upf -c osmo-upf.cfg
----

It is possible to configure multiple GTP devices in `osmo-upf.cfg`. Depending on
the Network Instance name, osmo-upf creates tunnel endpoints on the GTP device
with a matching IP address:

- The Network Instance IE in the PDR on the Access side determines the local IP
  address to use, see <<netinst>>.
- This local IP address in turn determines the GTP device to use.

It is possible for a GTP device to listen on ANY -- just omit the IP address in
the `dev` config. In this case, all Network Instance names will be served by
this GTP device. When using ANY, there should be exactly one GTP dev configured.

[[nftables]]
=== Configure Linux netfilter for `tunmap`

The Linux kernel netfilter module is used for GTP tunnel proxying, also known as
tunnel forwarding or tunnel mapping.

When using the netfilter module, you may set up `osmo-upf.cfg` for:
- GTP Echo (required)
- nft table name (optional)

[[gtp_echo]]
==== GTP Echo

You need to ensure that OsmoUPF responds to GTP Echo requests.
- A GTP device configured for `tunend` implicitly includes a GTP Echo service.
- For `tunmap`, no GTP Echo mechanism is implemented.

So, when your use case is `tunmap` only, you should still add a GTP device as
for `tunend`, only to provide the GTP Echo service.

Here are some options to do so:

If you have no GTP devices configured in `osmo-upf.cfg` yet, you can add a
single GTP device without a specific IP address, in order to respond to GTP-U
Echo requests on all interfaces to anyone that is asking:

----
tunend
 dev create gtp-echo
----

Note that `gtp-echo` is just an arbitrary GTP device name, choose any string
that makes a valid network device name and is still available, as in the `dev`
argument in the `ip addr show dev` command on Linux.

This will bind osmo-upf on 0.0.0.0:2152 to respond to GTP Echo requests.

If you would like to limit GTP Echo responses to specific network interfaces,
you need to add a separate GTP device per local IP address:

----
tunend
 dev create gtp-echo1 192.168.0.23
 dev create gtp-echo2 10.9.8.17
----

This will bind osmo-upf only on 192.168.0.23:2152 and 10.9.8.17:2152 to respond
to GTP Echo requests.

For creating and manipulating a GTP device in more versatile ways, see
<<gtp_module>>.

==== nft Table Name

For `tunmap`, `osmo-upf` creates a new nft table, under which it submits
rule sets for GTP tunnel proxying. This table name defaults to `osmo-upf`. A
custom table name can be configured in `osmo-upf.cfg` like this:

----
tunmap
 table-name my-table-name
----

When running more than one osmo-upf process on a system, pick distinct table
names to avoid name collisions in the nftables rulesets.

=== IP Forwarding

In order to allow forwarding GTP payloads, the Linux operating system must
be configured to allow IP forwarding.

Note that there are many distribution-specific ways to configure this, and there
might be higher-level firewall rule management software available like `ufw`.
You should configure firewall rules matching your distribution and setup.

To allow IP forwarding from and to all interfaces globally in a reboot-safe way,
you may put a line like this in /etc/sysctl.conf:

----
net.ipv4.ip_forward=1
----

To do the same in an ad-hoc way that is not reboot safe but takes effect
immediately:

----
sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
----

It is also possible to instruct the firewall to allow IP forwarding for specific
network devices only. For example, on a Debian based system, place an nft
ruleset like this in `/etc/nftables.conf`:

----
define gtp_netdevs = { eth0, eth23 };

table inet filter {
      chain forward {
              type filter hook forward priority filter; policy drop;
              iifname $gtp_netdevs oifname $gtp_netdevs udp dport 2152 accept
      }
}
----

This ruleset allows IP forwarding, but limited to the GTP-U port 2152,
and to two specific network devices eth0 and eth23.
