Skip to content

Plugins

Matthieu Baerts edited this page Nov 18, 2024 · 14 revisions

Overview

MPTCP path management in the Multipath TCP Daemon is implemented through plugins. Concrete path management strategies implement the mptcpd plugin API. For more details about the MPTCP path-manager, please see this global overview.

Note that the upstream MPTCP kernel implementation currently has two path-managers controllable via the net.mptcp.pm_type sysctl, and mptcpd can control both of them:

  • The in-kernel one (0, default): the same rules are applied to all connections. Address endpoints and limits can be set from the userspace to control its behavior, see the address-advertiser add_adv reference plugin.
  • The userspace one (1): different rules can be applied for each connection for advanced custom behaviour. The path-manager will then need to be controlled by a userspace daemon, see the single-subflow-per-interface sspi reference plugin.

Implementation

mptcpd leverages the Embedded Linux Library plugin interface for its underlying plugin infrastructure, and consequently expects plugins to use the ELL plugin conventions. At a basic level, this involves calling the ELL L_PLUGIN_DEFINE() macro with plugin-specific arguments, with the exception of the symbol argument which must be MPTCPD_PLUGIN_DESC. At program start mptcpd will then load all plugins in the plugin directory, and call the init function used in the L_PLUGIN_DEFINE() macro.

MPTCP Event Handlers

Plugins define each of the mptcpd plugin API functions found in the mptcpd_plugin_ops structure, and register those path management operations with mptcpd in the plugin init function by calling the mptcpd_plugin_register_ops() function. These functions each correspond to a specific MPTCP event (e.g. new connection, new subflow, etc.) defined in the Linux kernel MPTCP generic netlink API.

MPTCP Commands

There are times when a plugin may need to alter MPTCP connections or subflows, such as explicitly advertising new network addresses. mptcpd exposes a path management command API corresponding to the commands defined in the MPTCP generic netlink API that may be leveraged by plugins. The path management command functions are declared in the <mptcpd/path_manager.h> header.

MPTCP Network Monitoring

mptcpd monitors all MPTCP-capable network interfaces. Plugins may examine those network interfaces, along with associated network addresses, by retrieving a pointer to the network monitor from the mptcpd_pm_get_nm() function found in the mptcpd path manager API defined in <mptcpd/path_manager.h>. Iteration over the monitored network interfaces may then be performed through the mptcpd_nm_foreach_interface() function declared in the <mptcpd/network_monitor.h> header.

Sample Boilerplate Plugin

A very basic implementation for mptcpd plugin foo could look like the following:

#include <ell/ell.h>
#include <mptcpd/network_monitor.h>
#include <mptcpd/path_manager.h>
#include <mptcpd/plugin.h>

#define PLUGIN_NAME foo

static void foo_new_connection(mptcpd_token_t token,
                               struct sockaddr const *laddr,
                               struct sockaddr const *raddr,
                               struct mptcpd_pm *pm)
{
    // Handle creation of new MPTCP connection.
}

static void foo_connection_established(
    mptcpd_token_t token,
    struct sockaddr const *laddr,
    struct sockaddr const *raddr,
    struct mptcpd_pm *pm)
{
    // Handle establishment of new MPTCP connection.
}

static void foo_connection_closed(mptcpd_token_t token,
                                  struct mptcpd_pm *pm)
{
    // Handle MPTCP connection closure.
}

static void foo_new_address(mptcpd_token_t token,
                            mptcpd_aid_t addr_id,
                            struct sockaddr const *addr,
                            struct mptcpd_pm *pm)
{
    // Handle address advertised by MPTCP capable peer.
}

static void foo_address_removed(mptcpd_token_t token,
                                mptcpd_aid_t addr_id,
                                struct mptcpd_pm *pm)
{
    // Handle address no longer advertised by MPTCP capable peer.
}

static void foo_new_subflow(mptcpd_token_t token,
                            struct sockaddr const *laddr,
                            struct sockaddr const *raddr,
                            bool backup,
                            struct mptcpd_pm *pm)
{
    // Handle new subflow added to the MPTCP connection.
}

static void foo_subflow_closed(mptcpd_token_t token,
                               struct sockaddr const *laddr,
                               struct sockaddr const *raddr,
                               bool backup,
                               struct mptcpd_pm *pm)
{
    // Handle MPTCP subflow closure.
}

static void foo_subflow_priority(mptcpd_token_t token,
                                 struct sockaddr const *laddr,
                                 struct sockaddr const *raddr,
                                 bool backup,
                                 struct mptcpd_pm *pm)
{
    // Handle change in MPTCP subflow priority.
}

static struct mptcpd_plugin_ops const pm_ops = {
    .new_connection         = foo_new_connection,
    .connection_established = foo_connection_established,
    .connection_closed      = foo_connection_closed,
    .new_address            = foo_new_address,
    .address_removed        = foo_address_removed,
    .new_subflow            = foo_new_subflow,
    .subflow_closed         = foo_subflow_closed,
    .subflow_priority       = foo_subflow_priority
};

static int foo_init(void)
{
    static char const name[] = L_STRINGIFY(PLUGIN_NAME);

    if (!mptcpd_plugin_register_ops(name, &pm_ops)) {
        l_error("Failed to initialize plugin '%s'.", name);

        return -1;
    }

    return 0;
}

static void foo_exit(void)
{
}

L_PLUGIN_DEFINE(MPTCPD_PLUGIN_DESC,
                PLUGIN_NAME,
                "foo path management plugin",
                VERSION,
                L_PLUGIN_PRIORITY_DEFAULT,
                foo_init,
                foo_exit)

Build

Mptcpd plugins should be built as shared libraries. For example, given a GNU Autotool enabled mptcpd plugin called "foo", snippets of the configure.ac and Makefile.am could be implemented as follows.

configure.ac

AC_PREREQ([2.69])
AC_INIT([foo_plugin], [0.1])

AM_INIT_AUTOMAKE([foreign])
LT_INIT([disable-static])

AC_CONFIG_SRCDIR([foo.c])
AC_CONFIG_MACRO_DIRS([m4])

# ---------------------------------------------------------------
# Checks for programs.
# ---------------------------------------------------------------
AC_PROG_CC_STDC
AM_PROG_CC_C_O

# ---------------------------------------------------------------
# Checks for libraries.
# ---------------------------------------------------------------
# Find mptcpd.
PKG_CHECK_MODULES([MPTCPD], [mptcpd])

# Determine default mptcpd plugin directory.
PKG_CHECK_VAR([MPTCPD_PLUGINDIR], [mptcpd], [plugindir])

# ---------------------------------------------------------------
# Generate our build files.
# ---------------------------------------------------------------
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

Makefile.am

## "plugindir" specifies where plugins should be installed.
## Override as needed if the default mptcpd plugin directory
## is not used.
plugindir = @MPTCPD_PLUGINDIR@
plugin_LTLIBRARIES = foo.la

foo_la_SOURCES = foo.c
foo_la_CFLAGS  = $(MPTCPD_CFLAGS)
foo_la_LDFLAGS = -no-undefined -module -avoid-version
foo_la_LIBADD  = $(MPTCPD_LIBS)

Installation

Plugins should be installed in the plugin directory specified in the mptcpd configuration file. This normally corresponds to the compile-time default plugin directory (e.g. the result of the command pkg-config --variable=plugindir mptcpd), but the default could be potentially overridden if the mptcpd configuration was changed. For example, plugins would be installed in the directory /usr/lib/mptcpd if the mptcpd configuration file found at /etc/mptcpd/mptcpd.conf contains an entry such as the following:

# ----------------
# Plugin directory
# ----------------
plugin-dir=/usr/lib/mptcpd

or installed in the directory specified in the mptcpd --plugin-dir command line option. The order of precedence is:

  1. command line
  2. configuration file
  3. compile-time default