Skip to content

Plugins

Ossama Othman edited this page Nov 11, 2019 · 14 revisions

Overview

MPTCP path management in the Multipath TCP Daemon is implemented through plugins. Concrete path management strategies implement the mptcpd plugin API. One such example is 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. At program start mptcpd will then load all plugin 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, and register those path management operations with mptcpd in the plugin init function by the calling 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-cable 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.

Example

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
#define PLUGIN_VERSION "1.0"

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 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 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 new 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 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[] = #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",
                FOO_PLUGIN_VERSION,
                L_PLUGIN_PRIORITY_DEFAULT,
                foo_init,
                foo_exit)

Installation

Plugin binaries should be installed in the plugin directory specified in the mptcpd configuration file. 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

The exception to this rule is to install plugins in the directory provided in the mptcpd --plugin-dir command line option since it will override the directory specified in the configuration file.

Clone this wiki locally