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