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()