1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
.. _mpls:
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()
|