Line data Source code
1 : /*
2 : * sr_mpls_policy.c: SR-MPLS policies
3 : *
4 : * Copyright (c) 2016 Cisco and/or its affiliates. Licensed under the Apache
5 : * License, Version 2.0 (the "License"); you may not use this file except in
6 : * compliance with the License. You may obtain a copy of the License at:
7 : *
8 : * http://www.apache.org/licenses/LICENSE-2.0
9 : *
10 : * Unless required by applicable law or agreed to in writing, software
11 : * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 : * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 : * License for the specific language governing permissions and limitations
14 : * under the License.
15 : */
16 :
17 : /**
18 : * @file
19 : * @brief SR MPLS policy creation and application
20 : *
21 : * Create an SR policy.
22 : * An SR policy can be either of 'default' type or 'spray' type
23 : * An SR policy has attached a list of SID lists.
24 : * In case the SR policy is a default one it will load balance among them.
25 : * An SR policy has associated a BindingSID.
26 : * In case any packet arrives with MPLS_label == BindingSID then the SR policy
27 : * associated to such bindingSID will be applied to such packet.
28 : * Also, a BSID can be associated with a (Next-Hop, Color)
29 : *
30 : */
31 :
32 : #include <vlib/vlib.h>
33 : #include <vnet/vnet.h>
34 : #include <vnet/srmpls/sr_mpls.h>
35 : #include <vnet/fib/mpls_fib.h>
36 : #include <vnet/dpo/dpo.h>
37 : #include <vnet/ip/ip.h>
38 :
39 : #include <vppinfra/error.h>
40 : #include <vppinfra/elog.h>
41 :
42 : mpls_sr_main_t sr_mpls_main;
43 :
44 : /*************************** SR LB helper functions **************************/
45 : /**
46 : * @brief Creates a Segment List and adds it to an SR policy
47 : *
48 : * Creates a Segment List and adds it to the SR policy. Notice that the SL are
49 : * not necessarily unique. Hence there might be two Segment List within the
50 : * same SR Policy with exactly the same segments and same weight.
51 : *
52 : * @param sr_policy is the SR policy where the SL will be added
53 : * @param sl is a vector of IPv6 addresses composing the Segment List
54 : * @param weight is the weight of the SegmentList (for load-balancing purposes)
55 : * @param is_encap represents the mode (SRH insertion vs Encapsulation)
56 : *
57 : * @return pointer to the just created segment list
58 : */
59 : static inline mpls_sr_sl_t *
60 2 : create_sl (mpls_sr_policy_t * sr_policy, mpls_label_t * sl, u32 weight)
61 : {
62 2 : mpls_sr_main_t *sm = &sr_mpls_main;
63 : mpls_sr_sl_t *segment_list;
64 : u32 ii;
65 :
66 2 : pool_get (sm->sid_lists, segment_list);
67 2 : clib_memset (segment_list, 0, sizeof (*segment_list));
68 :
69 2 : vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
70 :
71 : /* Fill in segment list */
72 2 : segment_list->weight =
73 2 : (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
74 2 : segment_list->segments = vec_dup (sl);
75 :
76 : mpls_eos_bit_t eos;
77 6 : FOR_EACH_MPLS_EOS_BIT (eos)
78 : {
79 4 : fib_route_path_t path = {
80 : .frp_proto = DPO_PROTO_MPLS,
81 : .frp_sw_if_index = ~0,
82 : .frp_fib_index = 0,
83 4 : .frp_weight = segment_list->weight,
84 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
85 : .frp_label_stack = NULL,
86 4 : .frp_local_label = sl[0],
87 : };
88 :
89 4 : if (vec_len (sl) > 1)
90 : {
91 2 : vec_validate (path.frp_label_stack, vec_len (sl) - 2);
92 6 : for (ii = 1; ii < vec_len (sl); ii++)
93 : {
94 4 : path.frp_label_stack[ii - 1].fml_value = sl[ii];
95 : }
96 : }
97 : else
98 : {
99 : /*
100 : * add an impliciet NULL label to allow non-eos recursion
101 : */
102 2 : fib_mpls_label_t lbl = {
103 : .fml_value = MPLS_IETF_IMPLICIT_NULL_LABEL,
104 : };
105 2 : vec_add1 (path.frp_label_stack, lbl);
106 : }
107 :
108 4 : fib_route_path_t *paths = NULL;
109 4 : vec_add1 (paths, path);
110 :
111 : /* *INDENT-OFF* */
112 4 : fib_prefix_t pfx = {
113 : .fp_len = 21,
114 : .fp_proto = FIB_PROTOCOL_MPLS,
115 4 : .fp_label = sr_policy->bsid,
116 : .fp_eos = eos,
117 : .fp_payload_proto = DPO_PROTO_MPLS,
118 : };
119 : /* *INDENT-ON* */
120 :
121 4 : fib_table_entry_path_add2 (0,
122 : &pfx,
123 : FIB_SOURCE_SR,
124 4 : (sr_policy->type == SR_POLICY_TYPE_DEFAULT ?
125 : FIB_ENTRY_FLAG_NONE :
126 : FIB_ENTRY_FLAG_MULTICAST), paths);
127 4 : vec_free (paths);
128 : }
129 :
130 2 : return segment_list;
131 : }
132 :
133 : /******************************* SR rewrite API *******************************/
134 : /*
135 : * Three functions for handling sr policies: -> sr_mpls_policy_add ->
136 : * sr_mpls_policy_del -> sr_mpls_policy_mod All of them are API. CLI function
137 : * on sr_policy_command_fn
138 : */
139 :
140 : /**
141 : * @brief Create a new SR policy
142 : *
143 : * @param bsid is the bindingSID of the SR Policy
144 : * @param segments is a vector of MPLS labels composing the segment list
145 : * @param behavior is the behavior of the SR policy. (default//spray)
146 : * @param fib_table is the VRF where to install the FIB entry for the BSID
147 : * @param weight is the weight of this specific SID list
148 : *
149 : * @return 0 if correct, else error
150 : */
151 : int
152 2 : sr_mpls_policy_add (mpls_label_t bsid, mpls_label_t * segments,
153 : u8 behavior, u32 weight)
154 : {
155 2 : mpls_sr_main_t *sm = &sr_mpls_main;
156 2 : mpls_sr_policy_t *sr_policy = 0;
157 : uword *p;
158 :
159 2 : if (!sm->sr_policies_index_hash)
160 1 : sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
161 :
162 : /* MPLS SR policies cannot be created unless the MPLS table is present */
163 2 : if (~0 == fib_table_find (FIB_PROTOCOL_MPLS, MPLS_FIB_DEFAULT_TABLE_ID))
164 0 : return (VNET_API_ERROR_NO_SUCH_TABLE);
165 :
166 : /* Search for existing keys (BSID) */
167 2 : p = hash_get (sm->sr_policies_index_hash, bsid);
168 2 : if (p)
169 : {
170 : /* Add SR policy that already exists; complain */
171 0 : return -12;
172 : }
173 : /* Add an SR policy object */
174 2 : pool_get (sm->sr_policies, sr_policy);
175 2 : clib_memset (sr_policy, 0, sizeof (*sr_policy));
176 :
177 : /* the first policy needs to lock the MPLS table so it doesn't
178 : * disappear with policies in it */
179 2 : if (1 == pool_elts (sm->sr_policies))
180 2 : fib_table_find_or_create_and_lock (FIB_PROTOCOL_MPLS,
181 : MPLS_FIB_DEFAULT_TABLE_ID,
182 : FIB_SOURCE_SR);
183 2 : sr_policy->bsid = bsid;
184 2 : sr_policy->type = behavior;
185 2 : sr_policy->endpoint_type = 0;
186 2 : ip6_address_set_zero (&sr_policy->endpoint.ip6);
187 2 : sr_policy->color = (u32) ~ 0;
188 :
189 : /* Copy the key */
190 2 : hash_set (sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies);
191 :
192 : /* Create a segment list and add the index to the SR policy */
193 2 : create_sl (sr_policy, segments, weight);
194 :
195 2 : return 0;
196 : }
197 :
198 : /**
199 : * @brief Delete a SR policy
200 : *
201 : * @param bsid is the bindingSID of the SR Policy
202 : * @param index is the index of the SR policy
203 : *
204 : * @return 0 if correct, else error
205 : */
206 : int
207 2 : sr_mpls_policy_del (mpls_label_t bsid)
208 : {
209 2 : mpls_sr_main_t *sm = &sr_mpls_main;
210 2 : mpls_sr_policy_t *sr_policy = 0;
211 : mpls_sr_sl_t *segment_list;
212 : mpls_eos_bit_t eos;
213 : u32 *sl_index;
214 : uword *p;
215 :
216 2 : if (!sm->sr_policies_index_hash)
217 0 : sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
218 :
219 2 : p = hash_get (sm->sr_policies_index_hash, bsid);
220 2 : if (p)
221 2 : sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
222 : else
223 0 : return -1;
224 :
225 : /* Clean SID Lists */
226 4 : vec_foreach (sl_index, sr_policy->segments_lists)
227 : {
228 2 : segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
229 :
230 2 : fib_route_path_t path = {
231 : .frp_proto = DPO_PROTO_MPLS,
232 : .frp_sw_if_index = ~0,
233 : .frp_fib_index = 0,
234 2 : .frp_weight = segment_list->weight,
235 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
236 2 : .frp_local_label = segment_list->segments[0],
237 : };
238 :
239 2 : vec_add (path.frp_label_stack, segment_list + 1,
240 : vec_len (segment_list) - 1);
241 :
242 2 : fib_route_path_t *paths = NULL;
243 2 : vec_add1 (paths, path);
244 :
245 : /* remove each of the MPLS routes */
246 6 : FOR_EACH_MPLS_EOS_BIT (eos)
247 : {
248 : /* *INDENT-OFF* */
249 4 : fib_prefix_t pfx = {
250 : .fp_len = 21,
251 : .fp_proto = FIB_PROTOCOL_MPLS,
252 4 : .fp_label = sr_policy->bsid,
253 : .fp_eos = eos,
254 : .fp_payload_proto = DPO_PROTO_MPLS,
255 : };
256 : /* *INDENT-ON* */
257 :
258 4 : fib_table_entry_path_remove2 (0, &pfx, FIB_SOURCE_SR, paths);
259 : }
260 2 : vec_free (paths);
261 2 : vec_free (segment_list->segments);
262 2 : pool_put_index (sm->sid_lists, *sl_index);
263 : }
264 :
265 : /* If there is still traces of TE, make sure locks are released */
266 2 : if (sr_policy->endpoint_type != 0 && sr_policy->color != (u32) ~ 0)
267 : {
268 0 : sr_mpls_policy_assign_endpoint_color (bsid, NULL, 0, (u32) ~ 0);
269 : }
270 :
271 : /* Remove SR policy entry */
272 2 : hash_unset (sm->sr_policies_index_hash, sr_policy->bsid);
273 2 : pool_put (sm->sr_policies, sr_policy);
274 :
275 2 : if (0 == pool_elts (sm->sr_policies))
276 2 : fib_table_unlock (MPLS_FIB_DEFAULT_TABLE_ID,
277 : FIB_PROTOCOL_MPLS, FIB_SOURCE_SR);
278 :
279 2 : return 0;
280 : }
281 :
282 : /**
283 : * @brief Modify an existing SR policy
284 : *
285 : * The possible modifications are adding a new Segment List, modifying an
286 : * existing Segment List (modify the weight only) and delete a given
287 : * Segment List from the SR Policy.
288 : *
289 : * @param bsid is the bindingSID of the SR Policy
290 : * @param fib_table is the VRF where to install the FIB entry for the BSID
291 : * @param operation is the operation to perform (among the top ones)
292 : * @param segments is a vector of IPv6 address composing the segment list
293 : * @param sl_index is the index of the Segment List to modify/delete
294 : * @param weight is the weight of the sid list. optional.
295 : *
296 : * @return 0 ok, >0 index of SL, <0 error
297 : */
298 : int
299 0 : sr_mpls_policy_mod (mpls_label_t bsid, u8 operation,
300 : mpls_label_t * segments, u32 sl_index, u32 weight)
301 : {
302 0 : mpls_sr_main_t *sm = &sr_mpls_main;
303 0 : mpls_sr_policy_t *sr_policy = 0;
304 : mpls_sr_sl_t *segment_list;
305 : u32 *sl_index_iterate;
306 : uword *p;
307 :
308 0 : if (!sm->sr_policies_index_hash)
309 0 : sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
310 :
311 0 : p = hash_get (sm->sr_policies_index_hash, bsid);
312 0 : if (p)
313 0 : sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
314 : else
315 0 : return -1;
316 :
317 0 : if (operation == 1)
318 : { /* Add SR List to an existing SR policy */
319 : /* Create the new SL */
320 0 : segment_list = create_sl (sr_policy, segments, weight);
321 0 : return segment_list - sm->sid_lists;
322 : }
323 0 : else if (operation == 2)
324 : { /* Delete SR List from an existing SR
325 : * policy */
326 : /* Check that currently there are more than one SID list */
327 0 : if (vec_len (sr_policy->segments_lists) == 1)
328 0 : return -21;
329 :
330 : /*
331 : * Check that the SR list does exist and is assigned to the
332 : * sr policy
333 : */
334 0 : vec_foreach (sl_index_iterate, sr_policy->segments_lists)
335 0 : if (*sl_index_iterate == sl_index)
336 0 : break;
337 :
338 0 : if (*sl_index_iterate != sl_index)
339 0 : return -22;
340 :
341 : /* Remove the lucky SR list that is being kicked out */
342 0 : segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
343 :
344 : mpls_eos_bit_t eos;
345 0 : fib_route_path_t path = {
346 : .frp_proto = DPO_PROTO_MPLS,
347 : .frp_sw_if_index = ~0,
348 : .frp_fib_index = 0,
349 0 : .frp_weight = segment_list->weight,
350 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
351 0 : .frp_local_label = segment_list->segments[0],
352 : };
353 :
354 0 : vec_add (path.frp_label_stack, segment_list + 1,
355 : vec_len (segment_list) - 1);
356 :
357 0 : fib_route_path_t *paths = NULL;
358 0 : vec_add1 (paths, path);
359 :
360 0 : FOR_EACH_MPLS_EOS_BIT (eos)
361 : {
362 : /* *INDENT-OFF* */
363 0 : fib_prefix_t pfx = {
364 : .fp_len = 21,
365 : .fp_proto = FIB_PROTOCOL_MPLS,
366 0 : .fp_label = sr_policy->bsid,
367 : .fp_eos = eos,
368 : .fp_payload_proto = DPO_PROTO_MPLS,
369 : };
370 : /* *INDENT-ON* */
371 :
372 0 : fib_table_entry_path_remove2 (0, &pfx, FIB_SOURCE_SR, paths);
373 : }
374 :
375 0 : vec_free (paths);
376 0 : vec_free (segment_list->segments);
377 0 : pool_put_index (sm->sid_lists, sl_index);
378 0 : vec_del1 (sr_policy->segments_lists,
379 : sl_index_iterate - sr_policy->segments_lists);
380 : }
381 0 : else if (operation == 3)
382 : { /* Modify the weight of an existing
383 : * SR List */
384 : /* Find the corresponding SL */
385 0 : vec_foreach (sl_index_iterate, sr_policy->segments_lists)
386 0 : if (*sl_index_iterate == sl_index)
387 0 : break;
388 :
389 0 : if (*sl_index_iterate != sl_index)
390 0 : return -32;
391 :
392 : /* Change the weight */
393 0 : segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
394 :
395 : /* Update LB */
396 : mpls_eos_bit_t eos;
397 0 : fib_route_path_t path = {
398 : .frp_proto = DPO_PROTO_MPLS,
399 : .frp_sw_if_index = ~0,
400 : .frp_fib_index = 0,
401 0 : .frp_weight = segment_list->weight,
402 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
403 0 : .frp_local_label = segment_list->segments[0],
404 : };
405 :
406 0 : vec_add (path.frp_label_stack, segment_list + 1,
407 : vec_len (segment_list) - 1);
408 :
409 0 : fib_route_path_t *paths = NULL;
410 0 : vec_add1 (paths, path);
411 :
412 0 : FOR_EACH_MPLS_EOS_BIT (eos)
413 : {
414 : /* *INDENT-OFF* */
415 0 : fib_prefix_t pfx = {
416 : .fp_len = 21,
417 : .fp_proto = FIB_PROTOCOL_MPLS,
418 0 : .fp_label = sr_policy->bsid,
419 : .fp_eos = eos,
420 : .fp_payload_proto = DPO_PROTO_MPLS,
421 : };
422 : /* *INDENT-ON* */
423 :
424 0 : fib_table_entry_path_remove2 (0, &pfx, FIB_SOURCE_SR, paths);
425 : }
426 :
427 0 : segment_list->weight = weight;
428 :
429 0 : path.frp_weight = segment_list->weight;
430 :
431 0 : vec_free (paths);
432 0 : paths = NULL;
433 0 : vec_add1 (paths, path);
434 :
435 0 : FOR_EACH_MPLS_EOS_BIT (eos)
436 : {
437 : /* *INDENT-OFF* */
438 0 : fib_prefix_t pfx = {
439 : .fp_len = 21,
440 : .fp_proto = FIB_PROTOCOL_MPLS,
441 0 : .fp_label = sr_policy->bsid,
442 : .fp_eos = eos,
443 : .fp_payload_proto = DPO_PROTO_MPLS,
444 : };
445 : /* *INDENT-ON* */
446 :
447 0 : fib_table_entry_path_add2 (0,
448 : &pfx,
449 : FIB_SOURCE_SR,
450 0 : (sr_policy->type ==
451 : SR_POLICY_TYPE_DEFAULT ?
452 : FIB_ENTRY_FLAG_NONE :
453 : FIB_ENTRY_FLAG_MULTICAST), paths);
454 : }
455 : }
456 0 : return 0;
457 : }
458 :
459 : /**
460 : * @brief CLI for 'sr mpls policies' command family
461 : */
462 : static clib_error_t *
463 0 : sr_mpls_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
464 : vlib_cli_command_t * cmd)
465 : {
466 0 : int rv = -1;
467 0 : char is_del = 0, is_add = 0, is_mod = 0;
468 0 : char policy_set = 0;
469 : mpls_label_t bsid, next_label;
470 0 : u32 sl_index = (u32) ~ 0;
471 0 : u32 weight = (u32) ~ 0;
472 0 : mpls_label_t *segments = 0;
473 0 : u8 operation = 0;
474 0 : u8 is_spray = 0;
475 :
476 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
477 : {
478 0 : if (!is_add && !is_mod && !is_del && unformat (input, "add"))
479 0 : is_add = 1;
480 0 : else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
481 0 : is_del = 1;
482 0 : else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
483 0 : is_mod = 1;
484 0 : else if (!policy_set
485 0 : && unformat (input, "bsid %U", unformat_mpls_unicast_label,
486 : &bsid))
487 0 : policy_set = 1;
488 0 : else if (unformat (input, "weight %d", &weight));
489 0 : else if (unformat
490 : (input, "next %U", unformat_mpls_unicast_label, &next_label))
491 : {
492 0 : vec_add (segments, &next_label, 1);
493 : }
494 0 : else if (unformat (input, "add sl"))
495 0 : operation = 1;
496 0 : else if (unformat (input, "del sl index %d", &sl_index))
497 0 : operation = 2;
498 0 : else if (unformat (input, "mod sl index %d", &sl_index))
499 0 : operation = 3;
500 0 : else if (unformat (input, "spray"))
501 0 : is_spray = 1;
502 : else
503 0 : break;
504 : }
505 :
506 0 : if (!is_add && !is_mod && !is_del)
507 0 : return clib_error_return (0, "Incorrect CLI");
508 :
509 0 : if (!policy_set)
510 0 : return clib_error_return (0, "No SR policy BSID or index specified");
511 :
512 0 : if (is_add)
513 : {
514 0 : if (vec_len (segments) == 0)
515 0 : return clib_error_return (0, "No Segment List specified");
516 :
517 0 : rv = sr_mpls_policy_add (bsid, segments,
518 : (is_spray ? SR_POLICY_TYPE_SPRAY :
519 : SR_POLICY_TYPE_DEFAULT), weight);
520 0 : vec_free (segments);
521 : }
522 0 : else if (is_del)
523 0 : rv = sr_mpls_policy_del (bsid);
524 0 : else if (is_mod)
525 : {
526 0 : if (!operation)
527 0 : return clib_error_return (0, "No SL modification specified");
528 0 : if (operation != 1 && sl_index == (u32) ~ 0)
529 0 : return clib_error_return (0, "No Segment List index specified");
530 0 : if (operation == 1 && vec_len (segments) == 0)
531 0 : return clib_error_return (0, "No Segment List specified");
532 0 : if (operation == 3 && weight == (u32) ~ 0)
533 0 : return clib_error_return (0, "No new weight for the SL specified");
534 0 : rv = sr_mpls_policy_mod (bsid, operation, segments, sl_index, weight);
535 0 : vec_free (segments);
536 : }
537 0 : switch (rv)
538 : {
539 0 : case 0:
540 0 : break;
541 0 : case 1:
542 0 : return 0;
543 0 : case -12:
544 0 : return clib_error_return (0,
545 : "There is already a FIB entry for the BindingSID address.\n"
546 : "The SR policy could not be created.");
547 0 : case -21:
548 0 : return clib_error_return (0,
549 : "The selected SR policy only contains ONE segment list. "
550 : "Please remove the SR policy instead");
551 0 : case -22:
552 0 : return clib_error_return (0,
553 : "Could not delete the segment list. "
554 : "It is not associated with that SR policy.");
555 0 : case -23:
556 0 : return clib_error_return (0,
557 : "Could not delete the segment list. "
558 : "It is not associated with that SR policy.");
559 0 : case -32:
560 0 : return clib_error_return (0,
561 : "Could not modify the segment list. "
562 : "The given SL is not associated with such SR policy.");
563 0 : case VNET_API_ERROR_NO_SUCH_TABLE:
564 0 : return clib_error_return (0, "the Default MPLS table is not present");
565 0 : default:
566 0 : return clib_error_return (0, "BUG: sr policy returns %d", rv);
567 : }
568 0 : return 0;
569 : }
570 :
571 : /* *INDENT-OFF* */
572 285289 : VLIB_CLI_COMMAND(sr_mpls_policy_command, static)=
573 : {
574 : .path = "sr mpls policy",
575 : .short_help = "sr mpls policy [add||del||mod] bsid 2999 "
576 : "next 10 next 20 next 30 (weight 1) (spray)",
577 : .long_help = "TBD.\n",
578 : .function = sr_mpls_policy_command_fn,
579 : };
580 : /* *INDENT-ON* */
581 :
582 : /**
583 : * @brief CLI to display onscreen all the SR MPLS policies
584 : */
585 : static clib_error_t *
586 0 : show_sr_mpls_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
587 : vlib_cli_command_t * cmd)
588 : {
589 0 : mpls_sr_main_t *sm = &sr_mpls_main;
590 0 : mpls_sr_sl_t *segment_list = 0;
591 0 : mpls_sr_policy_t *sr_policy = 0;
592 0 : mpls_sr_policy_t **vec_policies = 0;
593 : mpls_label_t *label;
594 : u32 *sl_index;
595 : u8 *s;
596 0 : int i = 0;
597 :
598 0 : vlib_cli_output (vm, "SR MPLS policies:");
599 :
600 : /* *INDENT-OFF* */
601 0 : pool_foreach (sr_policy, sm->sr_policies) {
602 0 : vec_add1(vec_policies, sr_policy);
603 : }
604 : /* *INDENT-ON* */
605 :
606 0 : vec_foreach_index (i, vec_policies)
607 : {
608 0 : sr_policy = vec_policies[i];
609 0 : vlib_cli_output (vm, "[%u].-\tBSID: %U",
610 0 : (u32) (sr_policy - sm->sr_policies),
611 : format_mpls_unicast_label, sr_policy->bsid);
612 0 : switch (sr_policy->endpoint_type)
613 : {
614 0 : case SR_STEER_IPV6:
615 0 : vlib_cli_output (vm, "\tEndpoint: %U", format_ip6_address,
616 : &sr_policy->endpoint.ip6);
617 0 : vlib_cli_output (vm, "\tColor: %u", sr_policy->color);
618 0 : break;
619 0 : case SR_STEER_IPV4:
620 0 : vlib_cli_output (vm, "\tEndpoint: %U", format_ip4_address,
621 : &sr_policy->endpoint.ip4);
622 0 : vlib_cli_output (vm, "\tColor: %u", sr_policy->color);
623 0 : break;
624 0 : default:
625 0 : vlib_cli_output (vm, "\tTE disabled");
626 : }
627 0 : vlib_cli_output (vm, "\tType: %s",
628 0 : (sr_policy->type ==
629 : SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
630 0 : vlib_cli_output (vm, "\tSegment Lists:");
631 0 : vec_foreach (sl_index, sr_policy->segments_lists)
632 : {
633 0 : s = NULL;
634 0 : segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
635 0 : s = format (s, "\t[%u].- ", *sl_index);
636 0 : s = format (s, "< ");
637 0 : vec_foreach (label, segment_list->segments)
638 : {
639 0 : s = format (s, "%U, ", format_mpls_unicast_label, *label);
640 : }
641 0 : s = format (s, "\b\b > ");
642 0 : vlib_cli_output (vm, " %s", s);
643 : }
644 0 : vlib_cli_output (vm, "-----------");
645 : }
646 0 : vec_free (vec_policies);
647 0 : return 0;
648 : }
649 :
650 : /* *INDENT-OFF* */
651 285289 : VLIB_CLI_COMMAND(show_sr_mpls_policies_command, static)=
652 : {
653 : .path = "show sr mpls policies",
654 : .short_help = "show sr mpls policies",
655 : .function = show_sr_mpls_policies_command_fn,
656 : };
657 : /* *INDENT-ON* */
658 :
659 : /**
660 : * @brief Update the Endpoint,Color tuple of an SR policy
661 : *
662 : * @param bsid is the bindingSID of the SR Policy
663 : * @param endpoint represents the IP46 of the endpoint
664 : * @param color represents the color (u32)
665 : *
666 : * To reset to NULL use ~0 as parameters.
667 : *
668 : * @return 0 if correct, else error
669 : */
670 : int
671 0 : sr_mpls_policy_assign_endpoint_color (mpls_label_t bsid,
672 : ip46_address_t * endpoint,
673 : u8 endpoint_type, u32 color)
674 : {
675 0 : mpls_sr_main_t *sm = &sr_mpls_main;
676 0 : mpls_sr_policy_t *sr_policy = 0;
677 : uword *endpoint_table, *p, *old_value;
678 :
679 : ip46_address_t any;
680 0 : any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
681 :
682 0 : if (!sm->sr_policies_index_hash)
683 0 : sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
684 :
685 0 : p = hash_get (sm->sr_policies_index_hash, bsid);
686 0 : if (p)
687 0 : sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
688 : else
689 0 : return -1;
690 :
691 : /* If previous Endpoint, color existed, remove (NH,C) and (ANY,C) */
692 0 : if (sr_policy->endpoint_type)
693 : {
694 : endpoint_table =
695 0 : mhash_get (&sm->sr_policies_c2e2eclabel_hash, &sr_policy->color);
696 0 : if (!endpoint_table)
697 0 : return -2;
698 : old_value =
699 0 : mhash_get ((mhash_t *) endpoint_table, &sr_policy->endpoint);
700 :
701 : /* CID 180995 This should never be NULL unless the two hash tables
702 : * get out of sync */
703 0 : ALWAYS_ASSERT (old_value != NULL);
704 :
705 0 : fib_prefix_t pfx = { 0 };
706 0 : pfx.fp_proto = FIB_PROTOCOL_MPLS;
707 0 : pfx.fp_len = 21;
708 0 : pfx.fp_label = (u32) * old_value;
709 :
710 : mpls_eos_bit_t eos;
711 0 : FOR_EACH_MPLS_EOS_BIT (eos)
712 : {
713 0 : pfx.fp_eos = eos;
714 0 : fib_table_entry_path_remove (sm->fib_table_EC,
715 : &pfx,
716 : FIB_SOURCE_SR,
717 : DPO_PROTO_MPLS,
718 : NULL,
719 : ~0, 0, 1, FIB_ROUTE_PATH_FLAG_NONE);
720 : }
721 :
722 0 : old_value = mhash_get ((mhash_t *) endpoint_table, &any);
723 0 : pfx.fp_label = (u32) * old_value;
724 :
725 0 : FOR_EACH_MPLS_EOS_BIT (eos)
726 : {
727 0 : pfx.fp_eos = eos;
728 0 : fib_table_entry_path_remove (sm->fib_table_EC,
729 : &pfx,
730 : FIB_SOURCE_SR,
731 : DPO_PROTO_MPLS,
732 : NULL,
733 : ~0, 0, 1, FIB_ROUTE_PATH_FLAG_NONE);
734 : }
735 :
736 : /* Release the lock on (NH, Color) and (ANY, Color) */
737 0 : internal_label_unlock (sr_policy->endpoint, sr_policy->color);
738 0 : internal_label_unlock (any, sr_policy->color);
739 :
740 : /* Reset the values on the SR policy */
741 0 : sr_policy->endpoint_type = 0;
742 0 : sr_policy->endpoint.as_u64[0] = sr_policy->endpoint.as_u64[1] =
743 : (u64) ~ 0;
744 0 : sr_policy->color = (u32) ~ 0;
745 : }
746 :
747 0 : if (endpoint_type)
748 : {
749 0 : sr_policy->endpoint_type = endpoint_type;
750 0 : sr_policy->endpoint.as_u64[0] = endpoint->as_u64[0];
751 0 : sr_policy->endpoint.as_u64[1] = endpoint->as_u64[1];
752 0 : sr_policy->color = color;
753 :
754 0 : u32 label = find_or_create_internal_label (*endpoint, color);
755 0 : internal_label_lock (*endpoint, sr_policy->color);
756 :
757 : /* If FIB doesnt exist, create them */
758 0 : if (sm->fib_table_EC == (u32) ~ 0)
759 : {
760 0 : sm->fib_table_EC = fib_table_create_and_lock (FIB_PROTOCOL_MPLS,
761 : FIB_SOURCE_SR,
762 : "SR-MPLS Traffic Engineering (NextHop,Color)");
763 :
764 0 : fib_table_flush (sm->fib_table_EC, FIB_PROTOCOL_MPLS,
765 : FIB_SOURCE_SPECIAL);
766 : }
767 :
768 0 : fib_prefix_t pfx = { 0 };
769 0 : pfx.fp_proto = FIB_PROTOCOL_MPLS;
770 0 : pfx.fp_len = 21;
771 :
772 0 : fib_route_path_t path = {
773 : .frp_proto = DPO_PROTO_MPLS,
774 : .frp_sw_if_index = ~0,
775 : .frp_fib_index = 0,
776 : .frp_weight = 1,
777 : .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
778 : .frp_label_stack = 0
779 : };
780 0 : path.frp_local_label = sr_policy->bsid;
781 :
782 : //Add the entry to ANY,Color
783 0 : u32 any_label = find_or_create_internal_label (any, color);
784 0 : internal_label_lock (any, sr_policy->color);
785 :
786 0 : pfx.fp_eos = MPLS_EOS;
787 0 : path.frp_eos = MPLS_EOS;
788 :
789 0 : fib_route_path_t *paths = NULL;
790 0 : vec_add1 (paths, path);
791 :
792 0 : pfx.fp_label = label;
793 0 : fib_table_entry_update (sm->fib_table_EC,
794 : &pfx,
795 : FIB_SOURCE_SR,
796 : FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
797 :
798 0 : pfx.fp_label = any_label;
799 0 : fib_table_entry_update (sm->fib_table_EC,
800 : &pfx,
801 : FIB_SOURCE_SR,
802 : FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
803 :
804 0 : fib_mpls_label_t fml = {
805 : .fml_value = MPLS_IETF_IMPLICIT_NULL_LABEL,
806 : };
807 :
808 0 : vec_add1 (path.frp_label_stack, fml);
809 0 : pfx.fp_eos = MPLS_NON_EOS;
810 0 : path.frp_eos = MPLS_NON_EOS;
811 :
812 0 : paths = NULL;
813 0 : vec_add1 (paths, path);
814 :
815 0 : pfx.fp_label = label;
816 0 : fib_table_entry_update (sm->fib_table_EC,
817 : &pfx,
818 : FIB_SOURCE_SR,
819 : FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
820 :
821 0 : pfx.fp_label = any_label;
822 0 : fib_table_entry_update (sm->fib_table_EC,
823 : &pfx,
824 : FIB_SOURCE_SR,
825 : FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
826 : }
827 0 : return 0;
828 : }
829 :
830 : /**
831 : * @brief CLI to modify the Endpoint,Color of an SR policy
832 : */
833 : static clib_error_t *
834 0 : cli_sr_mpls_policy_ec_command_fn (vlib_main_t * vm, unformat_input_t * input,
835 : vlib_cli_command_t * cmd)
836 : {
837 : ip46_address_t endpoint;
838 0 : u32 color = (u32) ~ 0;
839 : mpls_label_t bsid;
840 0 : u8 endpoint_type = 0;
841 0 : char clear = 0, color_set = 0, bsid_set = 0;
842 :
843 0 : clib_memset (&endpoint, 0, sizeof (ip46_address_t));
844 :
845 : int rv;
846 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
847 : {
848 0 : if (!endpoint_type
849 0 : && unformat (input, "endpoint %U", unformat_ip6_address,
850 : &endpoint.ip6))
851 0 : endpoint_type = SR_STEER_IPV6;
852 0 : else if (!endpoint_type
853 0 : && unformat (input, "endpoint %U", unformat_ip4_address,
854 : &endpoint.ip4))
855 0 : endpoint_type = SR_STEER_IPV4;
856 0 : else if (!color_set && unformat (input, "color %u", &color))
857 0 : color_set = 1;
858 0 : else if (!bsid_set
859 0 : && unformat (input, "bsid %U", unformat_mpls_unicast_label,
860 : &bsid))
861 0 : bsid_set = 1;
862 0 : else if (!clear && unformat (input, "clear"))
863 0 : clear = 1;
864 : else
865 : break;
866 : }
867 :
868 0 : if (!bsid_set)
869 0 : return clib_error_return (0, "No BSID specified");
870 0 : if (!endpoint_type && !clear)
871 0 : return clib_error_return (0, "No Endpoint specified");
872 0 : if (!color_set && !clear)
873 0 : return clib_error_return (0, "No Color set");
874 :
875 : /* In case its a cleanup */
876 0 : if (clear)
877 : {
878 0 : ip6_address_set_zero (&endpoint.ip6);
879 0 : color = (u32) ~ 0;
880 : }
881 : rv =
882 0 : sr_mpls_policy_assign_endpoint_color (bsid, &endpoint, endpoint_type,
883 : color);
884 :
885 0 : if (rv)
886 0 : clib_error_return (0, "Error on Endpoint,Color");
887 :
888 0 : return 0;
889 : }
890 :
891 : /* *INDENT-OFF* */
892 285289 : VLIB_CLI_COMMAND(cli_sr_mpls_policy_ec_command, static)=
893 : {
894 : .path = "sr mpls policy te",
895 : .short_help = "sr mpls policy te bsid xxxxx endpoint x.x.x.x color 12341234",
896 : .function = cli_sr_mpls_policy_ec_command_fn,
897 : };
898 : /* *INDENT-ON* */
899 :
900 : /********************* SR MPLS Policy initialization ***********************/
901 : /**
902 : * @brief SR MPLS Policy initialization
903 : */
904 : clib_error_t *
905 575 : sr_mpls_policy_rewrite_init (vlib_main_t * vm)
906 : {
907 575 : mpls_sr_main_t *sm = &sr_mpls_main;
908 :
909 : /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
910 575 : sm->sr_policies_index_hash = NULL;
911 575 : sm->sr_policies_c2e2eclabel_hash.hash = NULL;
912 575 : return 0;
913 : }
914 :
915 69695 : VLIB_INIT_FUNCTION (sr_mpls_policy_rewrite_init);
916 :
917 : /*
918 : * fd.io coding-style-patch-verification: ON
919 : *
920 : * Local Variables: eval: (c-set-style "gnu") End:
921 : */
|