c11 safe string handling support
[vpp.git] / src / vnet / srmpls / sr_mpls_policy.c
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 create_sl (mpls_sr_policy_t * sr_policy, mpls_label_t * sl, u32 weight)
61 {
62   mpls_sr_main_t *sm = &sr_mpls_main;
63   mpls_sr_sl_t *segment_list;
64   u32 ii;
65
66   pool_get (sm->sid_lists, segment_list);
67   clib_memset (segment_list, 0, sizeof (*segment_list));
68
69   vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
70
71   /* Fill in segment list */
72   segment_list->weight =
73     (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
74   segment_list->segments = vec_dup (sl);
75
76   mpls_eos_bit_t eos;
77   FOR_EACH_MPLS_EOS_BIT (eos)
78   {
79     fib_route_path_t path = {
80       .frp_proto = DPO_PROTO_MPLS,
81       .frp_sw_if_index = ~0,
82       .frp_fib_index = 0,
83       .frp_weight = segment_list->weight,
84       .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
85       .frp_label_stack = NULL,
86       .frp_local_label = sl[0],
87     };
88
89     if (vec_len (sl) > 1)
90       {
91         vec_validate (path.frp_label_stack, vec_len (sl) - 2);
92         for (ii = 1; ii < vec_len (sl); ii++)
93           {
94             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         fib_mpls_label_t lbl = {
103           .fml_value = MPLS_IETF_IMPLICIT_NULL_LABEL,
104         };
105         vec_add1 (path.frp_label_stack, lbl);
106       }
107
108     fib_route_path_t *paths = NULL;
109     vec_add1 (paths, path);
110
111     /* *INDENT-OFF* */
112     fib_prefix_t pfx = {
113         .fp_len = 21,
114         .fp_proto = FIB_PROTOCOL_MPLS,
115         .fp_label = sr_policy->bsid,
116         .fp_eos = eos,
117         .fp_payload_proto = DPO_PROTO_MPLS,
118     };
119     /* *INDENT-ON* */
120
121     fib_table_entry_path_add2 (0,
122                                &pfx,
123                                FIB_SOURCE_SR,
124                                (sr_policy->type == SR_POLICY_TYPE_DEFAULT ?
125                                 FIB_ENTRY_FLAG_NONE :
126                                 FIB_ENTRY_FLAG_MULTICAST), paths);
127     vec_free (paths);
128   }
129
130   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 sr_mpls_policy_add (mpls_label_t bsid, mpls_label_t * segments,
153                     u8 behavior, u32 weight)
154 {
155   mpls_sr_main_t *sm = &sr_mpls_main;
156   mpls_sr_policy_t *sr_policy = 0;
157   uword *p;
158
159   if (!sm->sr_policies_index_hash)
160     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   if (~0 == fib_table_find (FIB_PROTOCOL_MPLS, MPLS_FIB_DEFAULT_TABLE_ID))
164     return (VNET_API_ERROR_NO_SUCH_TABLE);
165
166   /* Search for existing keys (BSID) */
167   p = hash_get (sm->sr_policies_index_hash, bsid);
168   if (p)
169     {
170       /* Add SR policy that already exists; complain */
171       return -12;
172     }
173   /* Add an SR policy object */
174   pool_get (sm->sr_policies, sr_policy);
175   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   if (1 == pool_elts (sm->sr_policies))
180     fib_table_find_or_create_and_lock (FIB_PROTOCOL_MPLS,
181                                        MPLS_FIB_DEFAULT_TABLE_ID,
182                                        FIB_SOURCE_SR);
183   sr_policy->bsid = bsid;
184   sr_policy->type = behavior;
185   sr_policy->endpoint_type = 0;
186   ip6_address_set_zero (&sr_policy->endpoint.ip6);
187   sr_policy->color = (u32) ~ 0;
188
189   /* Copy the key */
190   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   create_sl (sr_policy, segments, weight);
194
195   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 sr_mpls_policy_del (mpls_label_t bsid)
208 {
209   mpls_sr_main_t *sm = &sr_mpls_main;
210   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   if (!sm->sr_policies_index_hash)
217     sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
218
219   p = hash_get (sm->sr_policies_index_hash, bsid);
220   if (p)
221     sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
222   else
223     return -1;
224
225   /* Clean SID Lists */
226   vec_foreach (sl_index, sr_policy->segments_lists)
227   {
228     segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
229
230     fib_route_path_t path = {
231       .frp_proto = DPO_PROTO_MPLS,
232       .frp_sw_if_index = ~0,
233       .frp_fib_index = 0,
234       .frp_weight = segment_list->weight,
235       .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
236       .frp_local_label = segment_list->segments[0],
237     };
238
239     vec_add (path.frp_label_stack, segment_list + 1,
240              vec_len (segment_list) - 1);
241
242     fib_route_path_t *paths = NULL;
243     vec_add1 (paths, path);
244
245     /* remove each of the MPLS routes */
246     FOR_EACH_MPLS_EOS_BIT (eos)
247     {
248                         /* *INDENT-OFF* */
249                         fib_prefix_t    pfx = {
250                                 .fp_len = 21,
251                                 .fp_proto = FIB_PROTOCOL_MPLS,
252                                 .fp_label = sr_policy->bsid,
253                                 .fp_eos = eos,
254                                 .fp_payload_proto = DPO_PROTO_MPLS,
255                         };
256                         /* *INDENT-ON* */
257
258       fib_table_entry_path_remove2 (0, &pfx, FIB_SOURCE_SR, paths);
259     }
260     vec_free (paths);
261     vec_free (segment_list->segments);
262     pool_put_index (sm->sid_lists, *sl_index);
263   }
264
265   /* If there is still traces of TE, make sure locks are released */
266   if (sr_policy->endpoint_type != 0 && sr_policy->color != (u32) ~ 0)
267     {
268       sr_mpls_policy_assign_endpoint_color (bsid, NULL, 0, (u32) ~ 0);
269     }
270
271   /* Remove SR policy entry */
272   hash_unset (sm->sr_policies_index_hash, sr_policy->bsid);
273   pool_put (sm->sr_policies, sr_policy);
274
275   if (0 == pool_elts (sm->sr_policies))
276     fib_table_unlock (MPLS_FIB_DEFAULT_TABLE_ID,
277                       FIB_PROTOCOL_MPLS, FIB_SOURCE_SR);
278
279   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 sr_mpls_policy_mod (mpls_label_t bsid, u8 operation,
300                     mpls_label_t * segments, u32 sl_index, u32 weight)
301 {
302   mpls_sr_main_t *sm = &sr_mpls_main;
303   mpls_sr_policy_t *sr_policy = 0;
304   mpls_sr_sl_t *segment_list;
305   u32 *sl_index_iterate;
306   uword *p;
307
308   if (!sm->sr_policies_index_hash)
309     sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
310
311   p = hash_get (sm->sr_policies_index_hash, bsid);
312   if (p)
313     sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
314   else
315     return -1;
316
317   if (operation == 1)
318     {                           /* Add SR List to an existing SR policy */
319       /* Create the new SL */
320       segment_list = create_sl (sr_policy, segments, weight);
321       return segment_list - sm->sid_lists;
322     }
323   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       if (vec_len (sr_policy->segments_lists) == 1)
328         return -21;
329
330       /*
331        * Check that the SR list does exist and is assigned to the
332        * sr policy
333        */
334       vec_foreach (sl_index_iterate, sr_policy->segments_lists)
335         if (*sl_index_iterate == sl_index)
336         break;
337
338       if (*sl_index_iterate != sl_index)
339         return -22;
340
341       /* Remove the lucky SR list that is being kicked out */
342       segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
343
344       mpls_eos_bit_t eos;
345       fib_route_path_t path = {
346         .frp_proto = DPO_PROTO_MPLS,
347         .frp_sw_if_index = ~0,
348         .frp_fib_index = 0,
349         .frp_weight = segment_list->weight,
350         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
351         .frp_local_label = segment_list->segments[0],
352       };
353
354       vec_add (path.frp_label_stack, segment_list + 1,
355                vec_len (segment_list) - 1);
356
357       fib_route_path_t *paths = NULL;
358       vec_add1 (paths, path);
359
360       FOR_EACH_MPLS_EOS_BIT (eos)
361       {
362                         /* *INDENT-OFF* */
363                         fib_prefix_t    pfx = {
364                                 .fp_len = 21,
365                                 .fp_proto = FIB_PROTOCOL_MPLS,
366                                 .fp_label = sr_policy->bsid,
367                                 .fp_eos = eos,
368                                 .fp_payload_proto = DPO_PROTO_MPLS,
369                         };
370                         /* *INDENT-ON* */
371
372         fib_table_entry_path_remove2 (0, &pfx, FIB_SOURCE_SR, paths);
373       }
374
375       vec_free (paths);
376       vec_free (segment_list->segments);
377       pool_put_index (sm->sid_lists, sl_index);
378       vec_del1 (sr_policy->segments_lists,
379                 sl_index_iterate - sr_policy->segments_lists);
380     }
381   else if (operation == 3)
382     {                           /* Modify the weight of an existing
383                                  * SR List */
384       /* Find the corresponding SL */
385       vec_foreach (sl_index_iterate, sr_policy->segments_lists)
386         if (*sl_index_iterate == sl_index)
387         break;
388
389       if (*sl_index_iterate != sl_index)
390         return -32;
391
392       /* Change the weight */
393       segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
394
395       /* Update LB */
396       mpls_eos_bit_t eos;
397       fib_route_path_t path = {
398         .frp_proto = DPO_PROTO_MPLS,
399         .frp_sw_if_index = ~0,
400         .frp_fib_index = 0,
401         .frp_weight = segment_list->weight,
402         .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
403         .frp_local_label = segment_list->segments[0],
404       };
405
406       vec_add (path.frp_label_stack, segment_list + 1,
407                vec_len (segment_list) - 1);
408
409       fib_route_path_t *paths = NULL;
410       vec_add1 (paths, path);
411
412       FOR_EACH_MPLS_EOS_BIT (eos)
413       {
414                         /* *INDENT-OFF* */
415                         fib_prefix_t    pfx = {
416                                 .fp_len = 21,
417                                 .fp_proto = FIB_PROTOCOL_MPLS,
418                                 .fp_label = sr_policy->bsid,
419                                 .fp_eos = eos,
420                                 .fp_payload_proto = DPO_PROTO_MPLS,
421                         };
422                         /* *INDENT-ON* */
423
424         fib_table_entry_path_remove2 (0, &pfx, FIB_SOURCE_SR, paths);
425       }
426
427       segment_list->weight = weight;
428
429       path.frp_weight = segment_list->weight;
430
431       vec_free (paths);
432       paths = NULL;
433       vec_add1 (paths, path);
434
435       FOR_EACH_MPLS_EOS_BIT (eos)
436       {
437                         /* *INDENT-OFF* */
438                         fib_prefix_t    pfx = {
439                                 .fp_len = 21,
440                                 .fp_proto = FIB_PROTOCOL_MPLS,
441                                 .fp_label = sr_policy->bsid,
442                                 .fp_eos = eos,
443                                 .fp_payload_proto = DPO_PROTO_MPLS,
444                         };
445                         /* *INDENT-ON* */
446
447         fib_table_entry_path_add2 (0,
448                                    &pfx,
449                                    FIB_SOURCE_SR,
450                                    (sr_policy->type ==
451                                     SR_POLICY_TYPE_DEFAULT ?
452                                     FIB_ENTRY_FLAG_NONE :
453                                     FIB_ENTRY_FLAG_MULTICAST), paths);
454       }
455     }
456   return 0;
457 }
458
459 /**
460  * @brief CLI for 'sr mpls policies' command family
461  */
462 static clib_error_t *
463 sr_mpls_policy_command_fn (vlib_main_t * vm, unformat_input_t * input,
464                            vlib_cli_command_t * cmd)
465 {
466   int rv = -1;
467   char is_del = 0, is_add = 0, is_mod = 0;
468   char policy_set = 0;
469   mpls_label_t bsid, next_label;
470   u32 sl_index = (u32) ~ 0;
471   u32 weight = (u32) ~ 0;
472   mpls_label_t *segments = 0;
473   u8 operation = 0;
474   u8 is_spray = 0;
475
476   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
477     {
478       if (!is_add && !is_mod && !is_del && unformat (input, "add"))
479         is_add = 1;
480       else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
481         is_del = 1;
482       else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
483         is_mod = 1;
484       else if (!policy_set
485                && unformat (input, "bsid %U", unformat_mpls_unicast_label,
486                             &bsid))
487         policy_set = 1;
488       else if (unformat (input, "weight %d", &weight));
489       else if (unformat
490                (input, "next %U", unformat_mpls_unicast_label, &next_label))
491         {
492           vec_add (segments, &next_label, 1);
493         }
494       else if (unformat (input, "add sl"))
495         operation = 1;
496       else if (unformat (input, "del sl index %d", &sl_index))
497         operation = 2;
498       else if (unformat (input, "mod sl index %d", &sl_index))
499         operation = 3;
500       else if (unformat (input, "spray"))
501         is_spray = 1;
502       else
503         break;
504     }
505
506   if (!is_add && !is_mod && !is_del)
507     return clib_error_return (0, "Incorrect CLI");
508
509   if (!policy_set)
510     return clib_error_return (0, "No SR policy BSID or index specified");
511
512   if (is_add)
513     {
514       if (vec_len (segments) == 0)
515         return clib_error_return (0, "No Segment List specified");
516
517       rv = sr_mpls_policy_add (bsid, segments,
518                                (is_spray ? SR_POLICY_TYPE_SPRAY :
519                                 SR_POLICY_TYPE_DEFAULT), weight);
520       vec_free (segments);
521     }
522   else if (is_del)
523     rv = sr_mpls_policy_del (bsid);
524   else if (is_mod)
525     {
526       if (!operation)
527         return clib_error_return (0, "No SL modification specified");
528       if (operation != 1 && sl_index == (u32) ~ 0)
529         return clib_error_return (0, "No Segment List index specified");
530       if (operation == 1 && vec_len (segments) == 0)
531         return clib_error_return (0, "No Segment List specified");
532       if (operation == 3 && weight == (u32) ~ 0)
533         return clib_error_return (0, "No new weight for the SL specified");
534       rv = sr_mpls_policy_mod (bsid, operation, segments, sl_index, weight);
535       vec_free (segments);
536     }
537   switch (rv)
538     {
539     case 0:
540       break;
541     case 1:
542       return 0;
543     case -12:
544       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     case -21:
548       return clib_error_return (0,
549                                 "The selected SR policy only contains ONE segment list. "
550                                 "Please remove the SR policy instead");
551     case -22:
552       return clib_error_return (0,
553                                 "Could not delete the segment list. "
554                                 "It is not associated with that SR policy.");
555     case -23:
556       return clib_error_return (0,
557                                 "Could not delete the segment list. "
558                                 "It is not associated with that SR policy.");
559     case -32:
560       return clib_error_return (0,
561                                 "Could not modify the segment list. "
562                                 "The given SL is not associated with such SR policy.");
563     case VNET_API_ERROR_NO_SUCH_TABLE:
564       return clib_error_return (0, "the Default MPLS table is not present");
565     default:
566       return clib_error_return (0, "BUG: sr policy returns %d", rv);
567     }
568   return 0;
569 }
570
571 /* *INDENT-OFF* */
572 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 show_sr_mpls_policies_command_fn (vlib_main_t * vm, unformat_input_t * input,
587                                   vlib_cli_command_t * cmd)
588 {
589   mpls_sr_main_t *sm = &sr_mpls_main;
590   mpls_sr_sl_t *segment_list = 0;
591   mpls_sr_policy_t *sr_policy = 0;
592   mpls_sr_policy_t **vec_policies = 0;
593   mpls_label_t *label;
594   u32 *sl_index;
595   u8 *s;
596   int i = 0;
597
598   vlib_cli_output (vm, "SR MPLS policies:");
599
600         /* *INDENT-OFF* */
601         pool_foreach(sr_policy, sm->sr_policies, {
602                 vec_add1(vec_policies, sr_policy);
603         });
604         /* *INDENT-ON* */
605
606   vec_foreach_index (i, vec_policies)
607   {
608     sr_policy = vec_policies[i];
609     vlib_cli_output (vm, "[%u].-\tBSID: %U",
610                      (u32) (sr_policy - sm->sr_policies),
611                      format_mpls_unicast_label, sr_policy->bsid);
612     switch (sr_policy->endpoint_type)
613       {
614       case SR_STEER_IPV6:
615         vlib_cli_output (vm, "\tEndpoint: %U", format_ip6_address,
616                          &sr_policy->endpoint.ip6);
617         vlib_cli_output (vm, "\tColor: %u", sr_policy->color);
618         break;
619       case SR_STEER_IPV4:
620         vlib_cli_output (vm, "\tEndpoint: %U", format_ip4_address,
621                          &sr_policy->endpoint.ip4);
622         vlib_cli_output (vm, "\tColor: %u", sr_policy->color);
623         break;
624       default:
625         vlib_cli_output (vm, "\tTE disabled");
626       }
627     vlib_cli_output (vm, "\tType: %s",
628                      (sr_policy->type ==
629                       SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
630     vlib_cli_output (vm, "\tSegment Lists:");
631     vec_foreach (sl_index, sr_policy->segments_lists)
632     {
633       s = NULL;
634       segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
635       s = format (s, "\t[%u].- ", *sl_index);
636       s = format (s, "< ");
637       vec_foreach (label, segment_list->segments)
638       {
639         s = format (s, "%U, ", format_mpls_unicast_label, *label);
640       }
641       s = format (s, "\b\b > ");
642       vlib_cli_output (vm, "  %s", s);
643     }
644     vlib_cli_output (vm, "-----------");
645   }
646   vec_free (vec_policies);
647   return 0;
648 }
649
650 /* *INDENT-OFF* */
651 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 sr_mpls_policy_assign_endpoint_color (mpls_label_t bsid,
672                                       ip46_address_t * endpoint,
673                                       u8 endpoint_type, u32 color)
674 {
675   mpls_sr_main_t *sm = &sr_mpls_main;
676   mpls_sr_policy_t *sr_policy = 0;
677   uword *endpoint_table, *p, *old_value;
678
679   ip46_address_t any;
680   any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
681
682   if (!sm->sr_policies_index_hash)
683     sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
684
685   p = hash_get (sm->sr_policies_index_hash, bsid);
686   if (p)
687     sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
688   else
689     return -1;
690
691   /* If previous Endpoint, color existed, remove (NH,C) and (ANY,C) */
692   if (sr_policy->endpoint_type)
693     {
694       endpoint_table =
695         mhash_get (&sm->sr_policies_c2e2eclabel_hash, &sr_policy->color);
696       if (!endpoint_table)
697         return -2;
698       old_value =
699         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       ASSERT (old_value != NULL);
704
705       fib_prefix_t pfx = { 0 };
706       pfx.fp_proto = FIB_PROTOCOL_MPLS;
707       pfx.fp_len = 21;
708       pfx.fp_label = (u32) * old_value;
709
710       mpls_eos_bit_t eos;
711       FOR_EACH_MPLS_EOS_BIT (eos)
712       {
713         pfx.fp_eos = eos;
714         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       old_value = mhash_get ((mhash_t *) endpoint_table, &any);
723       pfx.fp_label = (u32) * old_value;
724
725       FOR_EACH_MPLS_EOS_BIT (eos)
726       {
727         pfx.fp_eos = eos;
728         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       internal_label_unlock (sr_policy->endpoint, sr_policy->color);
738       internal_label_unlock (any, sr_policy->color);
739
740       /* Reset the values on the SR policy */
741       sr_policy->endpoint_type = 0;
742       sr_policy->endpoint.as_u64[0] = sr_policy->endpoint.as_u64[1] =
743         (u64) ~ 0;
744       sr_policy->color = (u32) ~ 0;
745     }
746
747   if (endpoint_type)
748     {
749       sr_policy->endpoint_type = endpoint_type;
750       sr_policy->endpoint.as_u64[0] = endpoint->as_u64[0];
751       sr_policy->endpoint.as_u64[1] = endpoint->as_u64[1];
752       sr_policy->color = color;
753
754       u32 label = find_or_create_internal_label (*endpoint, color);
755       internal_label_lock (*endpoint, sr_policy->color);
756
757       /* If FIB doesnt exist, create them */
758       if (sm->fib_table_EC == (u32) ~ 0)
759         {
760           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           fib_table_flush (sm->fib_table_EC, FIB_PROTOCOL_MPLS,
765                            FIB_SOURCE_SPECIAL);
766         }
767
768       fib_prefix_t pfx = { 0 };
769       pfx.fp_proto = FIB_PROTOCOL_MPLS;
770       pfx.fp_len = 21;
771
772       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       path.frp_local_label = sr_policy->bsid;
781
782       //Add the entry to ANY,Color
783       u32 any_label = find_or_create_internal_label (any, color);
784       internal_label_lock (any, sr_policy->color);
785
786       pfx.fp_eos = MPLS_EOS;
787       path.frp_eos = MPLS_EOS;
788
789       fib_route_path_t *paths = NULL;
790       vec_add1 (paths, path);
791
792       pfx.fp_label = label;
793       fib_table_entry_update (sm->fib_table_EC,
794                               &pfx,
795                               FIB_SOURCE_SR,
796                               FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
797
798       pfx.fp_label = any_label;
799       fib_table_entry_update (sm->fib_table_EC,
800                               &pfx,
801                               FIB_SOURCE_SR,
802                               FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
803
804       fib_mpls_label_t fml = {
805         .fml_value = MPLS_IETF_IMPLICIT_NULL_LABEL,
806       };
807
808       vec_add1 (path.frp_label_stack, fml);
809       pfx.fp_eos = MPLS_NON_EOS;
810       path.frp_eos = MPLS_NON_EOS;
811
812       paths = NULL;
813       vec_add1 (paths, path);
814
815       pfx.fp_label = label;
816       fib_table_entry_update (sm->fib_table_EC,
817                               &pfx,
818                               FIB_SOURCE_SR,
819                               FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
820
821       pfx.fp_label = any_label;
822       fib_table_entry_update (sm->fib_table_EC,
823                               &pfx,
824                               FIB_SOURCE_SR,
825                               FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT, paths);
826     }
827   return 0;
828 }
829
830 /**
831  * @brief CLI to modify the Endpoint,Color of an SR policy
832  */
833 static clib_error_t *
834 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   u32 color = (u32) ~ 0;
839   mpls_label_t bsid;
840   u8 endpoint_type = 0;
841   char clear = 0, color_set = 0, bsid_set = 0;
842
843   clib_memset (&endpoint, 0, sizeof (ip46_address_t));
844
845   int rv;
846   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
847     {
848       if (!endpoint_type
849           && unformat (input, "endpoint %U", unformat_ip6_address,
850                        &endpoint.ip6))
851         endpoint_type = SR_STEER_IPV6;
852       else if (!endpoint_type
853                && unformat (input, "endpoint %U", unformat_ip4_address,
854                             &endpoint.ip4))
855         endpoint_type = SR_STEER_IPV4;
856       else if (!color_set && unformat (input, "color %u", &color))
857         color_set = 1;
858       else if (!bsid_set
859                && unformat (input, "bsid %U", unformat_mpls_unicast_label,
860                             &bsid))
861         bsid_set = 1;
862       else if (!clear && unformat (input, "clear"))
863         clear = 1;
864       else
865         break;
866     }
867
868   if (!bsid_set)
869     return clib_error_return (0, "No BSID specified");
870   if (!endpoint_type && !clear)
871     return clib_error_return (0, "No Endpoint specified");
872   if (!color_set && !clear)
873     return clib_error_return (0, "No Color set");
874
875   /* In case its a cleanup */
876   if (clear)
877     {
878       ip6_address_set_zero (&endpoint.ip6);
879       color = (u32) ~ 0;
880     }
881   rv =
882     sr_mpls_policy_assign_endpoint_color (bsid, &endpoint, endpoint_type,
883                                           color);
884
885   if (rv)
886     clib_error_return (0, "Error on Endpoint,Color");
887
888   return 0;
889 }
890
891 /* *INDENT-OFF* */
892 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 sr_mpls_policy_rewrite_init (vlib_main_t * vm)
906 {
907   mpls_sr_main_t *sm = &sr_mpls_main;
908
909   /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
910   sm->sr_policies_index_hash = NULL;
911   sm->sr_policies_c2e2eclabel_hash.hash = NULL;
912   return 0;
913 }
914
915 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  */