# MPLS howto

Short introduction into Linux MPLS. Requirements:

- kernel >= 4.4

- modules: mpls_router, mpls_iptunnel

- $ sudo sysctl net.mpls.platform_labels=$x, where $x – number of labels

- pyroute2 >= 0.4.0

## MPLS labels

Possible label formats:

    # int
    "newdst": 20

    # list of ints
    "newdst": [20]
    "newdst": [20, 30]

    # string
    "newdst": "20/30"

    # dict
    "newdst": {"label": 20}

    # list of dicts
    "newdst": [{"label": 20, "tc": 0, "bos": 0, "ttl": 16},
               {"label": 30, "tc": 0, "bos": 1, "ttl": 16}]

## IPRoute

### MPLS routes

Label swap:

    from pyroute2 import IPRoute
    from pyroute2.common import AF_MPLS

    ipr = IPRoute()
    # get the `eth0` interface's index:
    idx = ipr.link_lookup(ifname="eth0")[0]
    # create the request
    req = {"family": AF_MPLS,
           "oif": idx,
           "dst": 20,
           "newdst": [30]}
    # set up the route
    ipr.route("add", **req)

Please notice that “dst” can specify only one label, even being a list. Label push:

    req = {"family": AF_MPLS,
           "oif": idx,
           "dst": 20,
           "newdst": [20, 30]}
    ipr.route("add", **req)

One can set up also the via field:

    from socket import AF_INET

    req = {"family": AF_MPLS,
           "oif": idx,
           "dst": 20,
           "newdst": [30],
           "via": {"family": AF_INET,
                   "addr": "1.2.3.4"}}
    ipr.route("add", **req)

### MPLS lwtunnel

To inject IP packets into MPLS:

    req = {"dst": "1.2.3.0/24",
           "oif": idx,
           "encap": {"type": "mpls",
                     "labels": [202, 303]}}
    ipr.route("add", **req)

## NDB

Note

basic MPLS routes management in NDB since version 0.5.11

List MPLS routes:

    >>> from pyroute2.common import AF_MPLS
    >>> ndb.routes.dump().filter(family=AF_MPLS)
    ('localhost', 0, 28, 20, 0, 0, 254, 4, 0, 1, 0, ...
    ('localhost', 0, 28, 20, 0, 0, 254, 4, 0, 1, 0, ...

    >>> ndb.routes.dump().filter(family=AF_MPLS).select('oif', 'dst', 'newdst')
    (40627, '[{"label": 16, "tc": 0, "bos": 1, "ttl": 0}]', '[{"label": 500, ...
    (40627, '[{"label": 40, "tc": 0, "bos": 1, "ttl": 0}]', '[{"label": 40, ...

List lwtunnel routes:

    >>> ndb.routes.dump().filter(lambda x: x.encap is not None)
    ('localhost', 0, 2, 24, 0, 0, 254, 4, 0, 1, 16, '10.255.145.0', ...
    ('localhost', 0, 2, 24, 0, 0, 254, 4, 0, 1, 0, '192.168.142.0', ...

    >>> ndb.routes.dump().filter(lambda x: x.encap is not None).select('dst', 'encap')
    ('10.255.145.0', '[{"label": 20, "tc": 0, "bos": 0, "ttl": 0}, ...
    ('192.168.142.0', '[{"label": 20, "tc": 0, "bos": 0, "ttl": 0}, ...

Create MPLS routes:

    >>> from pyroute2.common import AF_MPLS
    >>> ndb.routes.create(family=AF_MPLS,
                          dst=128,                       # label
                          oif=1,                         # output interface
                          newdst=[128, 132]).commit()    # label stack

Create lwtunnel:

    >>> ndb.routes.create(dst='192.168.145.0/24',
                          gateway='192.168.140.5',
                          encap={'type': 'mpls',
                                 'labels': [128, 132]}).commit()