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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
|
OSPF Segment Routing
====================
This is an EXPERIMENTAL support of `RFC 8665`.
DON'T use it for production network.
Supported Features
------------------
* Automatic computation of Primary and Backup Adjacency SID with
Cisco experimental remote IP address
* SRGB & SRLB configuration
* Prefix configuration for Node SID with optional NO-PHP flag (Linux
kernel support both mode)
* Node MSD configuration (with Linux Kernel >= 4.10 a maximum of 32 labels
could be stack)
* Automatic provisioning of MPLS table
* Equal Cost Multi-Path (ECMP)
* Static route configuration with label stack up to 32 labels
* TI-LFA (for P2P interfaces only)
Interoperability
----------------
* Tested on various topology including point-to-point and LAN interfaces
in a mix of FRRouting instance and Cisco IOS-XR 6.0.x
* Check OSPF LSA conformity with latest wireshark release 2.5.0-rc
Implementation details
----------------------
Concepts
^^^^^^^^
Segment Routing used 3 different OPAQUE LSA in OSPF to carry the various
information:
* **Router Information:** flood the Segment Routing capabilities of the node.
This include the supported algorithms, the Segment Routing Global Block
(SRGB) and the Maximum Stack Depth (MSD).
* **Extended Link:** flood the Adjaceny and Lan Adjacency Segment Identifier
* **Extended Prefix:** flood the Prefix Segment Identifier
The implementation follows previous TE and Router Information codes. It used the
OPAQUE LSA functions defined in ospf_opaque.[c,h] as well as the OSPF API. This
latter is mandatory for the implementation as it provides the Callback to
Segment Routing functions (see below) when an Extended Link / Prefix or Router
Information LSA s are received.
Overview
^^^^^^^^
Following files where modified or added:
* ospd_ri.[c,h] have been modified to add the new TLVs for Segment Routing.
* ospf_ext.[c,h] implement RFC7684 as base support of Extended Link and Prefix
Opaque LSA.
* ospf_sr.[c,h] implement the earth of Segment Routing. It adds a new Segment
Routing database to manage Segment Identifiers per Link and Prefix and
Segment Routing enable node, Callback functions to process incoming LSA and
install MPLS FIB entry through Zebra.
The figure below shows the relation between the various files:
* ospf_sr.c centralized all the Segment Routing processing. It receives Opaque
LSA Router Information (4.0.0.0) from ospf_ri.c and Extended Prefix
(7.0.0.X) Link (8.0.0.X) from ospf_ext.c. Once received, it parse TLVs and
SubTLVs and store information in SRDB (which is defined in ospf_sr.h). For
each received LSA, NHLFE is computed and send to Zebra to add/remove new
MPLS labels entries and FEC. New CLI configurations are also centralized in
ospf_sr.c. This CLI will trigger the flooding of new LSA Router Information
(4.0.0.0), Extended Prefix (7.0.0.X) and Link (8.0.0.X) by ospf_ri.c,
respectively ospf_ext.c.
* ospf_ri.c send back to ospf_sr.c received Router Information LSA and update
Self Router Information LSA with parameters provided by ospf_sr.c i.e. SRGB
and MSD. It use ospf_opaque.c functions to send/received these Opaque LSAs.
* ospf_ext.c send back to ospf_sr.c received Extended Prefix and Link Opaque
LSA and send self Extended Prefix and Link Opaque LSA through ospf_opaque.c
functions.
::
+-----------+ +-------+
| | | |
| ospf_sr.c +-----+ SRDB |
+-----------+ +--+ | |
| +-^-------^-+ | +-------+
| | | | |
| | | | |
| | | | +--------+
| | | | |
+---v----------+ | | | +-----v-------+
| | | | | | |
| ospf_ri.c +--+ | +-------+ ospf_ext.c |
| LSA 4.0.0.0 | | | LSA 7.0.0.X |
| | | | LSA 8.0.0.X |
+---^----------+ | | |
| | +-----^-------+
| | |
| | |
| +--------v------------+ |
| | | |
| | ZEBRA: Labels + FEC | |
| | | |
| +---------------------+ |
| |
| |
| +---------------+ |
| | | |
+---------> ospf_opaque.c <---------+
| |
+---------------+
Figure 1: Overview of Segment Routing interaction
Module interactions
^^^^^^^^^^^^^^^^^^^
To process incoming LSA, the code is based on the capability to call `hook()`
functions when LSA are inserted or delete to / from the LSDB and the
possibility to register particular treatment for Opaque LSA. The first point
is provided by the OSPF API feature and the second by the Opaque implementation
itself. Indeed, it is possible to register callback function for a given Opaque
LSA ID (see `ospf_register_opaque_functab()` function defined in
`ospf_opaque.c`). Each time a new LSA is added to the LSDB, the
`new_lsa_hook()` function previously register for this LSA type is called. For
Opaque LSA it is the `ospf_opaque_lsa_install_hook()`. For deletion, it is
`ospf_opaque_lsa_delete_hook()`.
Note that incoming LSA which is already present in the LSDB will be inserted
after the old instance of this LSA remove from the LSDB. Thus, after the first
time, each incoming LSA will trigger a `delete` following by an `install`. This
is not very helpful to handle real LSA deletion. In fact, LSA deletion is done
by Flushing LSA i.e. flood LSA after setting its age to MAX_AGE. Then, a garbage
function has the role to remove all LSA with `age == MAX_AGE` in the LSDB. So,
to handle LSA Flush, the best is to look to the LSA age to determine if it is
an installation or a future deletion i.e. the flushed LSA is first store in the
LSDB with MAX_AGE waiting for the garbage collector function.
Router Information LSAs
^^^^^^^^^^^^^^^^^^^^^^^
To activate Segment Routing, new CLI command `segment-routing on` has been
introduced. When this command is activated, function
`ospf_router_info_update_sr()` is called to indicate to Router Information
process that Segment Routing TLVs must be flood. Same function is called to
modify the Segment Routing Global Block (SRGB) and Maximum Stack Depth (MSD)
TLV. Only Shortest Path First (SPF) Algorithm is supported, so no possibility
to modify this TLV is offer by the code.
When Opaque LSA Type 4 i.e. Router Information are stored in LSDB, function
`ospf_opaque_lsa_install_hook()` will call the previously registered function
`ospf_router_info_lsa_update()`. In turn, the function will simply trigger
`ospf_sr_ri_lsa_update()` or `ospf_sr_ri_lsa_delete` in function of the LSA
age. Before, it verifies that the LSA Opaque Type is 4 (Router Information).
Self Opaque LSA are not send back to the Segment Routing functions as
information are already stored.
Extended Link Prefix LSAs
^^^^^^^^^^^^^^^^^^^^^^^^^
Like for Router Information, Segment Routing is activate at the Extended
Link/Prefix level with new `segment-routing on` command. This triggers
automatically the flooding of Extended Link LSA for all ospf interfaces where
adjacency is full. For Extended Prefix LSA, the new CLI command
`segment-routing prefix ...` will trigger the flooding of Prefix SID
TLV/SubTLVs.
When Opaque LSA Type 7 i.e. Extended Prefix and Type 8 i.e. Extended Link are
store in the LSDB, `ospf_ext_pref_update_lsa()` respectively
`ospf_ext_link_update_lsa()` are called like for Router Information LSA. In
turn, they respectively trigger `ospf_sr_ext_prefix_lsa_update()` /
`ospf_sr_ext_link_lsa_update()` or `ospf_sr_ext_prefix_lsa_delete()` /
`ospf_sr_ext_link_lsa_delete()` if the LSA age is equal to MAX_AGE.
Zebra
^^^^^
When a new MPLS entry or new Forwarding Equivalent Class (FEC) must be added or
deleted in the data plane, `add_sid_nhlfe()` respectively `del_sid_nhlfe()` are
called. Once check the validity of labels, they are send to ZEBRA layer through
`ZEBRA_MPLS_LABELS_ADD` command, respectively `ZEBRA_MPLS_LABELS_DELETE`
command for deletion. This is completed by a new labelled route through
`ZEBRA_ROUTE_ADD` command, respectively `ZEBRA_ROUTE_DELETE` command.
TI-LFA
^^^^^^
Experimental support for Topology Independent LFA (Loop-Free Alternate), see
for example 'draft-bashandy-rtgwg-segment-routing-ti-lfa-05'. The related
files are `ospf_ti_lfa.c/h`.
The current implementation is rather naive and does not support the advanced
optimizations suggested in e.g. RFC7490 or RFC8102. It focuses on providing
the essential infrastructure which can also later be used to enhance the
algorithmic aspects.
Supported features:
* Link and node protection
* Intra-area support
* Proper use of Prefix- and Adjacency-SIDs in label stacks
* Asymmetric weights (using reverse SPF)
* Non-adjacent P/Q spaces
* Protection of Prefix-SIDs
If configured for every SPF run the routing table is enriched with additional
backup paths for every prefix. The corresponding Prefix-SIDs are updated with
backup paths too within the OSPF SR update task.
Informal High-Level Algorithm Description:
::
p_spaces = empty_list()
for every protected_resource (link or node):
p_space = generate_p_space(protected_resource)
p_space.q_spaces = empty_list()
for every destination that is affected by the protected_resource:
q_space = generate_q_space(destination)
# The label stack is stored in q_space
generate_label_stack(p_space, q_space)
# The p_space collects all its q_spaces
p_spaces.q_spaces.add(q_space)
p_spaces.add(p_space)
adjust_routing_table(p_spaces)
Possible Performance Improvements:
* Improve overall datastructures, get away from linked lists for vertices
* Don't calculate a Q space for every destination, but for a minimum set of
backup paths that cover all destinations in the post-convergence SPF. The
thinking here is that once a backup path is known that it is also a backup
path for all nodes on the path themselves. This can be done by using the
leafs of a trimmed minimum spanning tree generated out of the post-
convergence SPF tree for that particular P space.
* For an alternative (maybe better) optimization look at
https://tools.ietf.org/html/rfc7490#section-5.2.1.3 which describes using
the Q space of the node which is affected by e.g. a link failure. Note that
this optimization is topology dependent.
It is highly recommended to read e.g. `Segment Routing I/II` by Filsfils to
understand the basics of Ti-LFA.
Configuration
-------------
Linux Kernel
^^^^^^^^^^^^
In order to use OSPF Segment Routing, you must setup MPLS data plane. Up to
know, only Linux Kernel version >= 4.5 is supported.
First, the MPLS modules aren't loaded by default, so you'll need to load them
yourself:
::
modprobe mpls_router
modprobe mpls_gso
modprobe mpls_iptunnel
Then, you must activate MPLS on the interface you would used:
::
sysctl -w net.mpls.conf.enp0s9.input=1
sysctl -w net.mpls.conf.lo.input=1
sysctl -w net.mpls.platform_labels=1048575
The last line fix the maximum MPLS label value.
Once OSPFd start with Segment Routing, you could check that MPLS routes are
enable with:
::
ip -M route
ip route
The first command show the MPLS LFIB table while the second show the FIB
table which contains route with MPLS label encapsulation.
If you disable Penultimate Hop Popping with the `no-php-flag` (see below), you
MUST check that RP filter is not enable for the interface you intend to use,
especially the `lo` one. For that purpose, disable RP filtering with:
::
systcl -w net.ipv4.conf.all.rp_filter=0
sysctl -w net.ipv4.conf.lo.rp_filter=0
OSPFd
^^^^^
Here it is a simple example of configuration to enable Segment Routing. Note
that `opaque capability` and `router information` must be set to activate
Opaque LSA prior to Segment
Routing.
::
router ospf
ospf router-id 192.168.1.11
capability opaque
segment-routing on
segment-routing global-block 10000 19999 local-block 5000 5999
segment-routing node-msd 8
segment-routing prefix 192.168.1.11/32 index 1100
The first segment-routing statement enables it. The second and third one set
the SRGB and SRLB respectively, fourth line the MSD and finally, set the
Prefix SID index for a given prefix.
Note that only prefix of Loopback interface could be configured with a Prefix
SID. It is possible to add `no-php-flag` at the end of the prefix command to
disable Penultimate Hop Popping. This advertises to peers that they MUST NOT pop
the MPLS label prior to sending the packet.
Known limitations
-----------------
* Runs only within default VRF
* Only single Area is supported. ABR is not yet supported
* Only SPF algorithm is supported
* Extended Prefix Range is not supported
* With NO Penultimate Hop Popping, it is not possible to express a Segment
Path with an Adjacency SID due to the impossibility for the Linux Kernel to
perform double POP instruction.
Credits
-------
* Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
* Author: Olivier Dugeon <olivier.dugeon@orange.com>
* Copyright (C) 2016 - 2018 Orange Labs http://www.orange.com
This work has been performed in the framework of the H2020-ICT-2014
project 5GEx (Grant Agreement no. 671636), which is partially funded
by the European Commission.
|