FD.io VPP  v19.08.3-2-gbabecb413
Vector Packet Processing
sr_mpls_steering.c
Go to the documentation of this file.
1 /*
2  * sr_steering.c: ipv6 segment routing steering into SR policy
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 Packet steering into SR-MPLS Policies
20  *
21  * This file is in charge of handling the FIB appropiatly to steer packets
22  * through SR Policies as defined in 'sr_mpls_policy.c'. Notice that here
23  * we are only doing steering. SR policy application is done in
24  * sr_policy_rewrite.c
25  *
26  * Supports:
27  * - Steering of IPv6 traffic Destination Address based through BSID
28  * - Steering of IPv4 traffic Destination Address based through BSID
29  * - Steering of IPv4 and IPv6 traffic through N,C (SR CP)
30  */
31 
32 #include <vlib/vlib.h>
33 #include <vnet/vnet.h>
34 #include <vnet/srmpls/sr_mpls.h>
35 #include <vnet/ip/ip4_packet.h>
36 #include <vnet/ip/ip6_packet.h>
37 #include <vnet/fib/mpls_fib.h>
38 
39 #include <vppinfra/error.h>
40 #include <vppinfra/elog.h>
41 
42 #define SRMPLS_TE_OFFSET 50
43 
44 /**
45  * @brief function to sort the colors in descending order
46  */
47 int
48 sort_color_descent (const u32 * x, u32 * y)
49 {
50  return *y - *x;
51 }
52 
53 /********************* Internal (NH, C) labels *******************************/
54 /**
55  * @brief find the corresponding label for (endpoint, color) and lock it
56  * endpoint might be NULL or ANY
57  * NULL = 0, ANY=~0
58  */
59 u32
60 find_or_create_internal_label (ip46_address_t endpoint, u32 color)
61 {
63  uword *color_table, *result_label;
64 
67  sizeof (u32));
68 
69  color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
70  if (!color_table)
71  {
72  mhash_t color_t;
73  clib_memset (&color_t, 0, sizeof (mhash_t));
74  mhash_init (&color_t, sizeof (u32), sizeof (ip46_address_t));
76  (uword *) & color_t, NULL);
77  color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
78  }
79 
80  result_label = mhash_get ((mhash_t *) color_table, &endpoint);
81 
82  if (result_label)
83  return (u32) * result_label;
84 
85  /* Create and set a new internal label */
86  u32 *new_internal_label = 0;
87  pool_get (sm->ec_labels, new_internal_label);
88  *new_internal_label = 0;
89  mhash_set ((mhash_t *) color_table, &endpoint,
90  (new_internal_label - sm->ec_labels) + SRMPLS_TE_OFFSET, NULL);
91 
92  return (new_internal_label - sm->ec_labels) + SRMPLS_TE_OFFSET;
93 }
94 
95 always_inline void
96 internal_label_lock_co (ip46_address_t endpoint, u32 color, char co_bits)
97 {
98  ip46_address_t zero, any;
99  ip46_address_reset (&zero);
100  any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
101  switch (co_bits)
102  {
103  case SR_TE_CO_BITS_10:
104  internal_label_lock (endpoint, color);
105  internal_label_lock (zero, color);
106  internal_label_lock (any, color);
107  break;
108  case SR_TE_CO_BITS_01:
109  internal_label_lock (endpoint, color);
110  internal_label_lock (zero, color);
111  break;
112  case SR_TE_CO_BITS_00:
113  case SR_TE_CO_BITS_11:
114  internal_label_lock (endpoint, color);
115  break;
116  }
117 }
118 
119 /**
120  * @brief lock the label for (NH, C)
121  * endpoint might be NULL or ANY
122  * NULL = 0, ANY=~0
123  */
124 void
125 internal_label_lock (ip46_address_t endpoint, u32 color)
126 {
128  uword *color_table, *result_label;
129 
131  return;
132 
133  color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
134  if (!color_table)
135  return;
136 
137  result_label = mhash_get ((mhash_t *) color_table, &endpoint);
138 
139  if (!result_label)
140  return;
141 
142  /* Lock it */
143  u32 *label_lock =
144  pool_elt_at_index (sm->ec_labels, *result_label - SRMPLS_TE_OFFSET);
145  (*label_lock)++;
146 }
147 
148 
149 always_inline void
150 internal_label_unlock_co (ip46_address_t endpoint, u32 color, char co_bits)
151 {
152  ip46_address_t zero, any;
153  ip46_address_reset (&zero);
154  any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
155  switch (co_bits)
156  {
157  case SR_TE_CO_BITS_10:
158  internal_label_unlock (endpoint, color);
159  internal_label_unlock (zero, color);
160  internal_label_unlock (any, color);
161  break;
162  case SR_TE_CO_BITS_01:
163  internal_label_unlock (endpoint, color);
164  internal_label_unlock (zero, color);
165  break;
166  case SR_TE_CO_BITS_00:
167  case SR_TE_CO_BITS_11:
168  internal_label_unlock (endpoint, color);
169  break;
170  }
171 }
172 
173 /**
174  * @brief Release lock on label for (endpoint, color)
175  * endpoint might be NULL or ANY
176  * NULL = 0, ANY=~0
177  */
178 void
179 internal_label_unlock (ip46_address_t endpoint, u32 color)
180 {
182  uword *color_table, *result_label;
183 
185  return;
186 
187  color_table = mhash_get (&sm->sr_policies_c2e2eclabel_hash, &color);
188  if (!color_table)
189  return;
190 
191  result_label = mhash_get ((mhash_t *) color_table, &endpoint);
192 
193  if (!result_label)
194  return;
195 
196  u32 *label_lock =
197  pool_elt_at_index (sm->ec_labels, *result_label - SRMPLS_TE_OFFSET);
198  (*label_lock)--;
199 
200  if (*label_lock == 0)
201  {
202  pool_put (sm->ec_labels, label_lock);
203  mhash_unset ((mhash_t *) color_table, &endpoint, NULL);
204  if (mhash_elts ((mhash_t *) color_table) == 0)
205  {
206  mhash_free ((mhash_t *) color_table);
207  mhash_unset (&sm->sr_policies_c2e2eclabel_hash, &color, NULL);
209  {
213  FIB_SOURCE_SR);
214  sm->fib_table_EC = (u32) ~ 0;
215  }
216  }
217  }
218 }
219 
220 /********************* steering computation *********************************/
221 /**
222  * @brief function to update the FIB
223  */
224 void
226  steer_pl)
227 {
229  fib_prefix_t pfx = { 0 };
230 
231  u32 *internal_labels = 0;
232  ip46_address_t zero, any;
233  ip46_address_reset (&zero);
234  any.as_u64[0] = any.as_u64[1] = (u64) ~ 0;
235 
236  u32 *color_i = NULL;
237  vec_foreach (color_i, steer_pl->color)
238  {
239  switch (steer_pl->co_bits)
240  {
241  case SR_TE_CO_BITS_10:
242  vec_add1 (internal_labels,
244  *color_i));
245  vec_add1 (internal_labels,
246  find_or_create_internal_label (zero, *color_i));
247  vec_add1 (internal_labels,
248  find_or_create_internal_label (any, *color_i));
249  break;
250  case SR_TE_CO_BITS_01:
251  vec_add1 (internal_labels,
253  *color_i));
254  vec_add1 (internal_labels,
255  find_or_create_internal_label (zero, *color_i));
256  break;
257  case SR_TE_CO_BITS_00:
258  case SR_TE_CO_BITS_11:
259  vec_add1 (internal_labels,
261  *color_i));
262  break;
263  }
264  }
265 
266  /* Does hidden FIB already exist? */
267  if (sm->fib_table_EC == (u32) ~ 0)
268  {
271  "SR-MPLS Traffic Engineering (NextHop,Color)");
272 
275  }
276 
277  /* Add the corresponding FIB entries */
278  fib_route_path_t path = {
280  .frp_eos = MPLS_EOS,
281  .frp_sw_if_index = ~0,
282  .frp_fib_index = sm->fib_table_EC,
283  .frp_weight = 1,
284  .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
285  .frp_label_stack = 0
286  };
287  fib_route_path_t *paths = NULL;
288 
289  if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
290  {
292  pfx.fp_len = steer_pl->classify.mask_width;
293  pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
294  }
295  else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
296  {
298  pfx.fp_len = steer_pl->classify.mask_width;
299  pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
300  }
301 
302  if (steer_pl->vpn_label != (u32) ~ 0)
303  {
304  fib_mpls_label_t fml = {
305  .fml_value = steer_pl->vpn_label,
306  };
307  vec_add1 (path.frp_label_stack, fml);
308  path.frp_eos = MPLS_NON_EOS;
309  }
310 
311  u32 label_i;
312  vec_foreach_index (label_i, internal_labels)
313  {
314  path.frp_local_label = internal_labels[label_i];
315  path.frp_preference = label_i;
316  vec_add1 (paths, path);
317  }
318 
319  /* Finally we must add to FIB IGP to N */
320  clib_memcpy (&path.frp_addr, &steer_pl->next_hop,
321  sizeof (steer_pl->next_hop));
322  path.frp_preference = vec_len (internal_labels);
323  path.frp_label_stack = NULL;
324 
325  if (steer_pl->nh_type == SR_STEER_IPV6)
326  {
327  path.frp_proto = DPO_PROTO_IP6;
328  path.frp_fib_index =
330  (steer_pl->classify.fib_table !=
331  (u32) ~ 0 ? steer_pl->classify.fib_table : 0));
332  }
333  else if (steer_pl->nh_type == SR_STEER_IPV4)
334  {
335  path.frp_proto = DPO_PROTO_IP4;
336  path.frp_fib_index =
338  (steer_pl->classify.fib_table !=
339  (u32) ~ 0 ? steer_pl->classify.fib_table : 0));
340  }
341 
342  vec_add1 (paths, path);
343  if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
346  (steer_pl->classify.fib_table !=
347  (u32) ~ 0 ? steer_pl->classify.fib_table : 0)),
348  &pfx, FIB_SOURCE_SR,
350  else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
353  (steer_pl->classify.fib_table !=
354  (u32) ~ 0 ? steer_pl->classify.fib_table : 0)),
355  &pfx, FIB_SOURCE_SR,
357 
358  vec_free (paths);
359  paths = NULL;
360 }
361 
362 /**
363  * @brief Steer traffic L3 traffic through a given SR-MPLS policy
364  *
365  * @param is_del
366  * @param bsid is the bindingSID of the SR Policy (alt to sr_policy_index)
367  * @param sr_policy is the index of the SR Policy (alt to bsid)
368  * @param table_id is the VRF where to install the FIB entry for the BSID
369  * @param prefix is the IPv4/v6 address for L3 traffic type
370  * @param mask_width is the mask for L3 traffic type
371  * @param traffic_type describes the type of traffic
372  * @param next_hop SR TE Next-Hop
373  * @param nh_type is the AF of Next-Hop
374  * @param color SR TE color
375  * @param co_bits SR TE color-only bits
376  *
377  * @return 0 if correct, else error
378  */
379 int
381  ip46_address_t * prefix, u32 mask_width,
382  u8 traffic_type, ip46_address_t * next_hop,
383  u8 nh_type, u32 color, char co_bits,
384  mpls_label_t vpn_label)
385 {
388  mpls_sr_steering_policy_t *steer_pl;
389  fib_prefix_t pfx = { 0 };
390 
391  mpls_sr_policy_t *sr_policy = 0;
392  uword *p = 0;
393 
394  clib_memset (&key, 0, sizeof (sr_mpls_steering_key_t));
395 
396  if (traffic_type != SR_STEER_IPV4 && traffic_type != SR_STEER_IPV6)
397  return -1;
398 
399  /* Compute the steer policy key */
400  key.prefix.as_u64[0] = prefix->as_u64[0];
401  key.prefix.as_u64[1] = prefix->as_u64[1];
402  key.mask_width = mask_width;
403  key.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
404  key.traffic_type = traffic_type;
405 
406  /*
407  * Search for steering policy. If already exists we are adding a new
408  * color.
409  */
410  if (!sm->sr_steer_policies_hash.hash)
411  mhash_init (&sm->sr_steer_policies_hash, sizeof (uword),
412  sizeof (sr_mpls_steering_key_t));
413 
414  p = mhash_get (&sm->sr_steer_policies_hash, &key);
415  if (p)
416  {
417  steer_pl = pool_elt_at_index (sm->steer_policies, p[0]);
418  if (steer_pl->bsid != (u32) ~ 0)
419  return -1; //Means we are rewritting the steering. Not allowed.
420 
421  /* Means we are adding a color. Check that NH match. */
422  if (ip46_address_cmp (&steer_pl->next_hop, next_hop))
423  return -2;
424  if (vec_search (steer_pl->color, color) != ~0)
425  return -3;
426  if (steer_pl->co_bits != co_bits)
427  return -4; /* CO colors should be the same */
428  if (steer_pl->vpn_label != vpn_label)
429  return -5; /* VPN label should be the same */
430 
431  /* Remove the steering and ReDo it */
432  vec_add1 (steer_pl->color, color);
435  internal_label_lock_co (steer_pl->next_hop, color, steer_pl->co_bits);
436  return 0;
437  }
438 
439  /* Create a new steering policy */
440  pool_get (sm->steer_policies, steer_pl);
441  clib_memset (steer_pl, 0, sizeof (*steer_pl));
442  clib_memcpy (&steer_pl->classify.prefix, prefix, sizeof (ip46_address_t));
443  clib_memcpy (&steer_pl->next_hop, next_hop, sizeof (ip46_address_t));
444  steer_pl->nh_type = nh_type;
445  steer_pl->co_bits = co_bits;
446  steer_pl->classify.mask_width = mask_width;
447  steer_pl->classify.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
448  steer_pl->classify.traffic_type = traffic_type;
449  steer_pl->color = NULL;
450  steer_pl->vpn_label = vpn_label;
451 
452  /* Create and store key */
453  mhash_set (&sm->sr_steer_policies_hash, &key, steer_pl - sm->steer_policies,
454  NULL);
455 
456  /* Local steering */
457  if (bsid != (u32) ~ 0)
458  {
459  if (!sm->sr_policies_index_hash)
460  sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
461  steer_pl->bsid = bsid;
462  p = hash_get (sm->sr_policies_index_hash, bsid);
463  if (!p)
464  return -1;
465  sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
466 
467  fib_route_path_t path = {
469  .frp_local_label = sr_policy->bsid,
470  .frp_eos = MPLS_EOS,
471  .frp_sw_if_index = ~0,
472  .frp_fib_index = 0,
473  .frp_weight = 1,
474  .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
475  .frp_label_stack = 0
476  };
477  fib_route_path_t *paths = NULL;
478 
479  if (steer_pl->vpn_label != (u32) ~ 0)
480  {
481  fib_mpls_label_t fml = {
482  .fml_value = steer_pl->vpn_label,
483  };
484  vec_add1 (path.frp_label_stack, fml);
485  }
486 
487  /* FIB API calls - Recursive route through the BindingSID */
488  if (traffic_type == SR_STEER_IPV6)
489  {
491  pfx.fp_len = steer_pl->classify.mask_width;
492  pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
493  path.frp_fib_index = 0;
494  path.frp_preference = 0;
495  vec_add1 (paths, path);
498  (table_id != (u32) ~ 0 ? table_id : 0)),
499  &pfx, FIB_SOURCE_SR,
501  vec_free (paths);
502  }
503  else if (traffic_type == SR_STEER_IPV4)
504  {
506  pfx.fp_len = steer_pl->classify.mask_width;
507  pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
508  path.frp_fib_index = 0;
509  path.frp_preference = 0;
510  vec_add1 (paths, path);
513  (table_id != (u32) ~ 0 ? table_id : 0)),
514  &pfx, FIB_SOURCE_SR,
516  vec_free (paths);
517  }
518  }
519  /* Automated steering */
520  else
521  {
522  steer_pl->bsid = (u32) ~ 0;
523  vec_add1 (steer_pl->color, color);
525  internal_label_lock_co (steer_pl->next_hop, color, steer_pl->co_bits);
526  }
527  return 0;
528 }
529 
530 /**
531  * @brief Delete steering rule for an SR-MPLS policy
532  *
533  * @param is_del
534  * @param bsid is the bindingSID of the SR Policy (alt to sr_policy_index)
535  * @param sr_policy is the index of the SR Policy (alt to bsid)
536  * @param table_id is the VRF where to install the FIB entry for the BSID
537  * @param prefix is the IPv4/v6 address for L3 traffic type
538  * @param mask_width is the mask for L3 traffic type
539  * @param traffic_type describes the type of traffic
540  * @param next_hop SR TE Next-HOP
541  * @param nh_type is the AF of Next-Hop
542  * @param color SR TE color
543  *
544  * @return 0 if correct, else error
545  */
546 int
548  u8 traffic_type, u32 table_id, u32 color)
549 {
552  mpls_sr_steering_policy_t *steer_pl;
553  fib_prefix_t pfx = { 0 };
554  uword *p = 0;
555 
556  clib_memset (&key, 0, sizeof (sr_mpls_steering_key_t));
557 
558  /* Compute the steer policy key */
559  if (traffic_type != SR_STEER_IPV4 && traffic_type != SR_STEER_IPV6)
560  return -1;
561 
562  key.prefix.as_u64[0] = prefix->as_u64[0];
563  key.prefix.as_u64[1] = prefix->as_u64[1];
564  key.mask_width = mask_width;
565  key.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
566  key.traffic_type = traffic_type;
567 
568  if (!sm->sr_steer_policies_hash.hash)
569  mhash_init (&sm->sr_steer_policies_hash, sizeof (uword),
570  sizeof (sr_mpls_steering_key_t));
571 
572  /* Search for the item */
573  p = mhash_get (&sm->sr_steer_policies_hash, &key);
574 
575  if (!p)
576  return -1;
577 
578  /* Retrieve Steer Policy function */
579  steer_pl = pool_elt_at_index (sm->steer_policies, p[0]);
580 
581  if (steer_pl->bsid == (u32) ~ 0)
582  {
583  /* Remove the color from the color vector */
584  vec_del1 (steer_pl->color, vec_search (steer_pl->color, color));
585 
586  if (vec_len (steer_pl->color))
587  {
588  /* Reorder Colors */
591  /* Remove all the locks for this ones... */
592  internal_label_unlock_co (steer_pl->next_hop, color,
593  steer_pl->co_bits);
594  return 0;
595  }
596  else
597  {
598  vec_free (steer_pl->color);
599  /* Remove FIB entry */
600  if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
601  {
603  pfx.fp_len = steer_pl->classify.mask_width;
604  pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
607  steer_pl->classify.fib_table), &pfx,
608  FIB_SOURCE_SR);
609  }
610  else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
611  {
613  pfx.fp_len = steer_pl->classify.mask_width;
614  pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
617  steer_pl->classify.fib_table), &pfx,
618  FIB_SOURCE_SR);
619  }
620  /* Remove all the locks for this ones... */
621  internal_label_unlock_co (steer_pl->next_hop, color,
622  steer_pl->co_bits);
623  }
624  }
625  else //Remove by BSID
626  {
627  if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
628  {
630  pfx.fp_len = steer_pl->classify.mask_width;
631  pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
634  steer_pl->classify.fib_table), &pfx,
635  FIB_SOURCE_SR);
636  }
637  else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
638  {
640  pfx.fp_len = steer_pl->classify.mask_width;
641  pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
644  steer_pl->classify.fib_table), &pfx,
645  FIB_SOURCE_SR);
646  }
647  }
648  /* Delete SR steering policy entry */
649  pool_put (sm->steer_policies, steer_pl);
650  mhash_unset (&sm->sr_steer_policies_hash, &key, NULL);
651  if (mhash_elts (&sm->sr_steer_policies_hash) == 0)
652  {
654  sm->sr_steer_policies_hash.hash = NULL;
655  }
656  return 0;
657 }
658 
659 static clib_error_t *
661  vlib_cli_command_t * cmd)
662 {
663  int is_del = 0;
664 
665  ip46_address_t prefix, nh;
666  u32 dst_mask_width = 0;
667  u8 traffic_type = 0;
668  u8 nh_type = 0;
669  u32 fib_table = (u32) ~ 0, color = (u32) ~ 0;
670  u32 co_bits = 0;
671 
672  mpls_label_t bsid, vpn_label = (u32) ~ 0;
673 
674  u8 sr_policy_set = 0;
675 
676  clib_memset (&prefix, 0, sizeof (ip46_address_t));
677  clib_memset (&nh, 0, sizeof (ip46_address_t));
678 
679  int rv;
681  {
682  if (unformat (input, "del"))
683  is_del = 1;
684  else if (!traffic_type
685  && unformat (input, "l3 %U/%d", unformat_ip6_address,
686  &prefix.ip6, &dst_mask_width))
687  traffic_type = SR_STEER_IPV6;
688  else if (!traffic_type
689  && unformat (input, "l3 %U/%d", unformat_ip4_address,
690  &prefix.ip4, &dst_mask_width))
691  traffic_type = SR_STEER_IPV4;
692  else if (!sr_policy_set
693  && unformat (input, "via sr policy bsid %U",
695  sr_policy_set = 1;
696  else if (!sr_policy_set
697  && unformat (input, "via next-hop %U color %d co %d",
698  unformat_ip4_address, &nh.ip4, &color, &co_bits))
699  {
700  sr_policy_set = 1;
701  nh_type = SR_STEER_IPV4;
702  }
703  else if (!sr_policy_set
704  && unformat (input, "via next-hop %U color %d co %d",
705  unformat_ip6_address, &nh.ip6, &color, &co_bits))
706  {
707  sr_policy_set = 1;
708  nh_type = SR_STEER_IPV6;
709  }
710  else if (fib_table == (u32) ~ 0
711  && unformat (input, "fib-table %d", &fib_table));
712  else if (unformat (input, "vpn-label %U",
713  unformat_mpls_unicast_label, &vpn_label));
714  else
715  break;
716  }
717 
718  if (!traffic_type)
719  return clib_error_return (0, "No L3 traffic specified");
720  if (!sr_policy_set)
721  return clib_error_return (0, "No SR policy specified");
722 
723  /* Make sure that the prefixes are clean */
724  if (traffic_type == SR_STEER_IPV4)
725  {
726  u32 mask =
727  (dst_mask_width ? (0xFFFFFFFFu >> (32 - dst_mask_width)) : 0);
728  prefix.ip4.as_u32 &= mask;
729  }
730  else if (traffic_type == SR_STEER_IPV6)
731  {
732  ip6_address_t mask;
733  ip6_address_mask_from_width (&mask, dst_mask_width);
734  ip6_address_mask (&prefix.ip6, &mask);
735  }
736 
737  if (nh_type)
738  bsid = (u32) ~ 0;
739 
740  if (is_del)
741  rv =
742  sr_mpls_steering_policy_del (&prefix, dst_mask_width,
743  traffic_type, fib_table, color);
744 
745  else
746  rv =
747  sr_mpls_steering_policy_add (bsid, fib_table, &prefix, dst_mask_width,
748  traffic_type, &nh, nh_type, color, co_bits,
749  vpn_label);
750 
751  switch (rv)
752  {
753  case 0:
754  break;
755  case 1:
756  return 0;
757  case -1:
758  return clib_error_return (0, "Incorrect API usage.");
759  case -2:
760  return clib_error_return (0, "The Next-Hop does not match.");
761  case -3:
762  return clib_error_return (0, "The color already exists.");
763  case -4:
764  return clib_error_return (0, "The co-bits do not match.");
765  case -5:
766  return clib_error_return (0, "The VPN-labels do not match.");
767  default:
768  return clib_error_return (0, "BUG: sr steer policy returns %d", rv);
769  }
770  return 0;
771 }
772 
773 /* *INDENT-OFF* */
774 VLIB_CLI_COMMAND(sr_mpls_steer_policy_command, static)=
775 {
776  .path = "sr mpls steer",
777  .short_help = "sr mpls steer (del) l3 <ip_addr/mask> "
778  "via [sr policy bsid <mpls_label> || next-hop <ip46_addr> color <u32> co <0|1|2|3> ](fib-table <fib_table_index>)(vpn-label 500)",
779  .long_help =
780  "\tSteer L3 traffic through an existing SR policy.\n"
781  "\tExamples:\n"
782  "\t\tsr steer l3 2001::/64 via sr_policy bsid 29999\n"
783  "\t\tsr steer del l3 2001::/64 via sr_policy bsid 29999\n"
784  "\t\tsr steer l3 2001::/64 via next-hop 1.1.1.1 color 1234 co 0\n"
785  "\t\tsr steer l3 2001::/64 via next-hop 2001::1 color 1234 co 2 vpn-label 500\n",
787 };
788 /* *INDENT-ON* */
789 
790 static clib_error_t *
792  unformat_input_t * input,
793  vlib_cli_command_t * cmd)
794 {
796  mpls_sr_steering_policy_t **steer_policies = 0;
797  mpls_sr_steering_policy_t *steer_pl;
798 
799  int i;
800 
801  vlib_cli_output (vm, "SR MPLS steering policies:");
802  /* *INDENT-OFF* */
803  pool_foreach(steer_pl, sm->steer_policies, ({
804  vec_add1(steer_policies, steer_pl);
805  }));
806  /* *INDENT-ON* */
807  for (i = 0; i < vec_len (steer_policies); i++)
808  {
809  vlib_cli_output (vm, "==========================");
810  steer_pl = steer_policies[i];
811  if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
812  {
813  vlib_cli_output (vm, "Prefix: %U/%d via:",
815  &steer_pl->classify.prefix.ip4,
816  steer_pl->classify.mask_width);
817  }
818  else if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
819  {
820  vlib_cli_output (vm, "Prefix: %U/%d via:",
822  &steer_pl->classify.prefix.ip6,
823  steer_pl->classify.mask_width);
824  }
825 
826  if (steer_pl->bsid != (u32) ~ 0)
827  {
828  vlib_cli_output (vm, "· BSID %U",
829  format_mpls_unicast_label, steer_pl->bsid);
830  }
831  else
832  {
833  if (steer_pl->nh_type == SR_STEER_IPV4)
834  {
835  vlib_cli_output (vm, "· Next-hop %U",
836  format_ip4_address, &steer_pl->next_hop.ip4);
837  }
838  else if (steer_pl->nh_type == SR_STEER_IPV6)
839  {
840  vlib_cli_output (vm, "· Next-hop %U",
841  format_ip6_address, &steer_pl->next_hop.ip6);
842  }
843 
844  u32 *color_i = 0;
845  u8 *s = NULL;
846  s = format (s, "[ ");
847  vec_foreach (color_i, steer_pl->color)
848  {
849  s = format (s, "%d, ", *color_i);
850  }
851  s = format (s, "\b\b ]");
852  vlib_cli_output (vm, "· Color %s", s);
853 
854  switch (steer_pl->co_bits)
855  {
856  case SR_TE_CO_BITS_00:
857  vlib_cli_output (vm, "· CO-bits: 00");
858  break;
859  case SR_TE_CO_BITS_01:
860  vlib_cli_output (vm, "· CO-bits: 01");
861  break;
862  case SR_TE_CO_BITS_10:
863  vlib_cli_output (vm, "· CO-bits: 10");
864  break;
865  case SR_TE_CO_BITS_11:
866  vlib_cli_output (vm, "· CO-bits: 11");
867  break;
868  }
869  }
870  }
871  return 0;
872 }
873 
874 /* *INDENT-OFF* */
875 VLIB_CLI_COMMAND(show_sr_mpls_steering_policies_command, static)=
876 {
877  .path = "show sr mpls steering policies",
878  .short_help = "show sr mpls steering policies",
880 };
881 /* *INDENT-ON* */
882 
883 clib_error_t *
885 {
887 
888  /* Init memory for function keys */
889  sm->sr_steer_policies_hash.hash = NULL;
890 
891  sm->fib_table_EC = (u32) ~ 0;
892  sm->ec_labels = 0;
893 
894  return 0;
895 }
896 
897 /* *INDENT-OFF* */
899 /* *INDENT-ON* */
900 
901 /*
902  * fd.io coding-style-patch-verification: ON
903  *
904  * Local Variables: eval: (c-set-style "gnu") End:
905  */
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:212
Definition: mhash.h:46
#define vec_foreach_index(var, v)
Iterate over vector indices.
ip46_address_t frp_addr
The next-hop address.
Definition: fib_types.h:501
#define SR_STEER_IPV6
Definition: sr_mpls.h:42
u8 traffic_type
Traffic type (IPv4, IPv6, L2)
Definition: sr_mpls.h:88
#define SR_STEER_IPV4
Definition: sr_mpls.h:41
mpls_eos_bit_t frp_eos
EOS bit for the resolving label.
Definition: fib_types.h:512
u32 * color
Vector of SR TE colors.
Definition: sr_mpls.h:98
A representation of a path as described by a route producer.
Definition: fib_types.h:485
ip46_address_t next_hop
SR TE NH.
Definition: sr_mpls.h:96
vl_api_fib_path_nh_t nh
Definition: fib_types.api:126
void internal_label_lock(ip46_address_t endpoint, u32 color)
lock the label for (NH, C) endpoint might be NULL or ANY NULL = 0, ANY=~0
unsigned long u64
Definition: types.h:89
fib_node_index_t fib_table_entry_update(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, fib_route_path_t *paths)
Update an entry to have a new set of paths.
Definition: fib_table.c:739
uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:346
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
ip46_address_t prefix
IP address of the prefix.
Definition: sr_mpls.h:85
#define SR_TE_CO_BITS_01
Definition: sr_mpls.h:45
u32 mpls_label_t
A label value only, i.e.
Definition: packet.h:26
fib_node_index_t fib_table_entry_path_add2(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, fib_route_path_t *rpaths)
Add n paths to an entry (aka route) in the FIB.
Definition: fib_table.c:574
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
word any
Definition: types.h:139
int i
mhash_t sr_steer_policies_hash
Definition: sr_mpls.h:121
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
dpo_proto_t frp_proto
The protocol of the address below.
Definition: fib_types.h:490
vl_api_mprefix_t prefix
Definition: ip.api:456
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:236
static void ip6_address_mask(ip6_address_t *a, const ip6_address_t *mask)
Definition: ip6_packet.h:268
int sort_color_descent(const u32 *x, u32 *y)
function to sort the colors in descending order
#define ip46_address_cmp(ip46_1, ip46_2)
Definition: ip6_packet.h:92
unsigned char u8
Definition: types.h:56
u32 fib_table
VRF of the prefix.
Definition: sr_mpls.h:87
unformat_function_t unformat_mpls_unicast_label
Definition: mpls.h:81
#define clib_memcpy(d, s, n)
Definition: string.h:180
Definition: fib_entry.h:289
format_function_t format_ip4_address
Definition: format.h:75
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:493
unformat_function_t unformat_ip4_address
Definition: format.h:70
static clib_error_t * show_sr_mpls_steering_policies_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
#define always_inline
Definition: clib.h:99
void fib_table_flush(u32 fib_index, fib_protocol_t proto, fib_source_t source)
Flush all entries from a table for the source.
Definition: fib_table.c:1345
Aggregate type for a prefix.
Definition: fib_types.h:203
#define clib_error_return(e, args...)
Definition: error.h:99
unsigned int u32
Definition: types.h:88
#define vec_search(v, E)
Search a vector for the index of the entry that matches.
Definition: vec.h:940
u32 fib_table_find(fib_protocol_t proto, u32 table_id)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1080
u16 fp_len
The mask length.
Definition: fib_types.h:207
#define SRMPLS_TE_OFFSET
#define hash_get(h, key)
Definition: hash.h:249
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:514
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:226
uword mhash_set_mem(mhash_t *h, void *key, uword *new_value, uword *old_value)
Definition: mhash.c:264
static const __m128i zero
Definition: aes_gcm.c:39
struct _unformat_input_t unformat_input_t
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:286
Configuration for each label value in the output-stack.
Definition: fib_types.h:440
fib_mpls_label_t * frp_label_stack
The outgoing MPLS label Stack.
Definition: fib_types.h:546
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:804
mpls_sr_steering_policy_t * steer_policies
Definition: sr_mpls.h:118
clib_error_t * sr_mpls_steering_init(vlib_main_t *vm)
static uword mhash_set(mhash_t *h, void *key, uword new_value, uword *old_value)
Definition: mhash.h:117
int sr_mpls_steering_policy_add(mpls_label_t bsid, u32 table_id, ip46_address_t *prefix, u32 mask_width, u8 traffic_type, ip46_address_t *next_hop, u8 nh_type, u32 color, char co_bits, mpls_label_t vpn_label)
Steer traffic L3 traffic through a given SR-MPLS policy.
void fib_table_unlock(u32 fib_index, fib_protocol_t proto, fib_source_t source)
Take a reference counting lock on the table.
Definition: fib_table.c:1253
mpls_label_t bsid
BindingSID (key)
Definition: sr_mpls.h:66
mpls_label_t vpn_label
Definition: sr_mpls.h:100
static clib_error_t * sr_mpls_steer_policy_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
unformat_function_t unformat_ip6_address
Definition: format.h:91
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
int sr_mpls_steering_policy_del(ip46_address_t *prefix, u32 mask_width, u8 traffic_type, u32 table_id, u32 color)
Delete steering rule for an SR-MPLS policy.
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
void mhash_init(mhash_t *h, uword n_value_bytes, uword n_key_bytes)
Definition: mhash.c:168
format_function_t format_ip6_address
Definition: format.h:93
vlib_main_t * vm
Definition: buffer.c:323
uint32_t mask_width(const boost::asio::ip::address &addr)
Get the prefix mask length of a host route from the boost address.
Definition: prefix.cpp:273
sr_mpls_steering_key_t classify
Traffic classification.
Definition: sr_mpls.h:94
u32 mask_width
Mask width of the prefix.
Definition: sr_mpls.h:86
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
void fib_table_entry_delete(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Delete a FIB entry.
Definition: fib_table.c:869
mpls_label_t fml_value
The label value.
Definition: fib_types.h:445
static uword mhash_elts(mhash_t *m)
Definition: mhash.h:137
mpls_sr_policy_t * sr_policies
Definition: sr_mpls.h:112
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:161
#define hash_create(elts, value_bytes)
Definition: hash.h:696
Segment Routing main datastructure.
Definition: sr_mpls.h:106
void compute_sr_te_automated_steering_fib_entry(mpls_sr_steering_policy_t *steer_pl)
function to update the FIB
static uword * mhash_get(mhash_t *h, const void *key)
Definition: mhash.h:110
static void mhash_free(mhash_t *h)
Definition: mhash.h:149
u8 frp_preference
A path preference.
Definition: fib_types.h:591
static void internal_label_lock_co(ip46_address_t endpoint, u32 color, char co_bits)
uword * sr_policies_index_hash
Definition: sr_mpls.h:115
static void internal_label_unlock_co(ip46_address_t endpoint, u32 color, char co_bits)
mpls_label_t bsid
SR Policy index.
Definition: sr_mpls.h:95
uword * hash
Definition: mhash.h:69
#define SR_TE_CO_BITS_10
Definition: sr_mpls.h:46
#define SR_TE_CO_BITS_11
Definition: sr_mpls.h:47
vl_api_mfib_path_t paths[n_paths]
Definition: ip.api:458
format_function_t format_mpls_unicast_label
Definition: mpls.h:71
mpls_label_t frp_local_label
The MPLS local Label to reursively resolve through.
Definition: fib_types.h:508
#define ip46_address_reset(ip46)
Definition: ip6_packet.h:91
mhash_t sr_policies_c2e2eclabel_hash
SR TE.
Definition: sr_mpls.h:125
u32 * ec_labels
Definition: sr_mpls.h:129
u32 find_or_create_internal_label(ip46_address_t endpoint, u32 color)
find the corresponding label for (endpoint, color) and lock it endpoint might be NULL or ANY NULL = 0...
SRv6 and SR-MPLS.
Definition: fib_entry.h:63
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 uword
Definition: types.h:112
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:983
typedef key
Definition: ipsec.api:247
char co_bits
Color-Only bits.
Definition: sr_mpls.h:99
Segment Routing MPLS data structures definitions.
Special sources.
Definition: fib_entry.h:45
void internal_label_unlock(ip46_address_t endpoint, u32 color)
Release lock on label for (endpoint, color) endpoint might be NULL or ANY NULL = 0, ANY=~0.
static void ip6_address_mask_from_width(ip6_address_t *a, u32 width)
Definition: ip6_packet.h:284
Steering db key.
Definition: sr_mpls.h:83
mpls_sr_main_t sr_mpls_main
#define vec_foreach(var, vec)
Vector iterator.
u32 fib_table_EC
Definition: sr_mpls.h:127
#define SR_TE_CO_BITS_00
Definition: sr_mpls.h:44
u32 table_id
Definition: fib_types.api:118
u32 fib_table_create_and_lock(fib_protocol_t proto, fib_source_t src, const char *const fmt,...)
Create a new table with no table ID.
Definition: fib_table.c:1158
u32 frp_fib_index
The FIB index to lookup the nexthop Only valid for recursive paths.
Definition: fib_types.h:537
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:772
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171