FD.io VPP  v18.01.2-1-g9b554f3
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  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);
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  vec_add1 (path.frp_label_stack, steer_pl->vpn_label);
305  path.frp_eos = MPLS_NON_EOS;
306  }
307 
308  u32 label_i;
309  vec_foreach_index (label_i, internal_labels)
310  {
311  path.frp_local_label = internal_labels[label_i];
312  path.frp_preference = label_i;
313  vec_add1 (paths, path);
314  }
315 
316  /* Finally we must add to FIB IGP to N */
317  clib_memcpy (&path.frp_addr, &steer_pl->next_hop,
318  sizeof (steer_pl->next_hop));
319  path.frp_preference = vec_len (internal_labels);
320  path.frp_label_stack = NULL;
321 
322  if (steer_pl->nh_type == SR_STEER_IPV6)
323  {
324  path.frp_proto = DPO_PROTO_IP6;
325  path.frp_fib_index =
327  (steer_pl->classify.fib_table !=
328  (u32) ~ 0 ? steer_pl->classify.fib_table : 0));
329  }
330  else if (steer_pl->nh_type == SR_STEER_IPV4)
331  {
332  path.frp_proto = DPO_PROTO_IP4;
333  path.frp_fib_index =
335  (steer_pl->classify.fib_table !=
336  (u32) ~ 0 ? steer_pl->classify.fib_table : 0));
337  }
338 
339  vec_add1 (paths, path);
340  if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
343  (steer_pl->classify.fib_table !=
344  (u32) ~ 0 ? steer_pl->classify.fib_table : 0)),
345  &pfx, FIB_SOURCE_SR,
347  else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
350  (steer_pl->classify.fib_table !=
351  (u32) ~ 0 ? steer_pl->classify.fib_table : 0)),
352  &pfx, FIB_SOURCE_SR,
354 
355  vec_free (paths);
356  paths = NULL;
357 }
358 
359 /**
360  * @brief Steer traffic L3 traffic through a given SR-MPLS policy
361  *
362  * @param is_del
363  * @param bsid is the bindingSID of the SR Policy (alt to sr_policy_index)
364  * @param sr_policy is the index of the SR Policy (alt to bsid)
365  * @param table_id is the VRF where to install the FIB entry for the BSID
366  * @param prefix is the IPv4/v6 address for L3 traffic type
367  * @param mask_width is the mask for L3 traffic type
368  * @param traffic_type describes the type of traffic
369  * @param next_hop SR TE Next-Hop
370  * @param nh_type is the AF of Next-Hop
371  * @param color SR TE color
372  * @param co_bits SR TE color-only bits
373  *
374  * @return 0 if correct, else error
375  */
376 int
378  ip46_address_t * prefix, u32 mask_width,
379  u8 traffic_type, ip46_address_t * next_hop,
380  u8 nh_type, u32 color, char co_bits,
381  mpls_label_t vpn_label)
382 {
385  mpls_sr_steering_policy_t *steer_pl;
386  fib_prefix_t pfx = { 0 };
387 
388  mpls_sr_policy_t *sr_policy = 0;
389  uword *p = 0;
390 
391  memset (&key, 0, sizeof (sr_mpls_steering_key_t));
392 
393  /* Compute the steer policy key */
394  if (traffic_type == SR_STEER_IPV4 || traffic_type == SR_STEER_IPV6)
395  {
396  key.prefix.as_u64[0] = prefix->as_u64[0];
397  key.prefix.as_u64[1] = prefix->as_u64[1];
398  key.mask_width = mask_width;
399  key.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
400  }
401  else
402  return -1;
403 
404  key.traffic_type = traffic_type;
405 
406  if (traffic_type != SR_STEER_IPV4 && traffic_type != SR_STEER_IPV6)
407  return -1;
408 
409  /*
410  * Search for steering policy. If already exists we are adding a new
411  * color.
412  */
413  if (!sm->sr_steer_policies_hash.hash)
414  mhash_init (&sm->sr_steer_policies_hash, sizeof (uword),
415  sizeof (sr_mpls_steering_key_t));
416 
417  p = mhash_get (&sm->sr_steer_policies_hash, &key);
418  if (p)
419  {
420  steer_pl = pool_elt_at_index (sm->steer_policies, p[0]);
421  if (steer_pl->bsid != (u32) ~ 0)
422  return -1; //Means we are rewritting the steering. Not allowed.
423 
424  /* Means we are adding a color. Check that NH match. */
425  if (ip46_address_cmp (&steer_pl->next_hop, next_hop))
426  return -2;
427  if (vec_search (steer_pl->color, color) != ~0)
428  return -3;
429  if (steer_pl->co_bits != co_bits)
430  return -4; /* CO colors should be the same */
431  if (steer_pl->vpn_label != vpn_label)
432  return -5; /* VPN label should be the same */
433 
434  /* Remove the steering and ReDo it */
435  vec_add1 (steer_pl->color, color);
438  internal_label_lock_co (steer_pl->next_hop, color, steer_pl->co_bits);
439  return 0;
440  }
441 
442  /* Create a new steering policy */
443  pool_get (sm->steer_policies, steer_pl);
444  memset (steer_pl, 0, sizeof (*steer_pl));
445  clib_memcpy (&steer_pl->classify.prefix, prefix, sizeof (ip46_address_t));
446  clib_memcpy (&steer_pl->next_hop, next_hop, sizeof (ip46_address_t));
447  steer_pl->nh_type = nh_type;
448  steer_pl->co_bits = co_bits;
449  steer_pl->classify.mask_width = mask_width;
450  steer_pl->classify.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
451  steer_pl->classify.traffic_type = traffic_type;
452  steer_pl->color = NULL;
453  steer_pl->vpn_label = vpn_label;
454 
455  /* Create and store key */
456  mhash_set (&sm->sr_steer_policies_hash, &key, steer_pl - sm->steer_policies,
457  NULL);
458 
459  /* Local steering */
460  if (bsid != (u32) ~ 0)
461  {
462  if (!sm->sr_policies_index_hash)
463  sm->sr_policies_index_hash = hash_create (0, sizeof (mpls_label_t));
464  steer_pl->bsid = bsid;
465  p = hash_get (sm->sr_policies_index_hash, bsid);
466  if (!p)
467  return -1;
468  sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
469 
470  fib_route_path_t path = {
472  .frp_local_label = sr_policy->bsid,
473  .frp_eos = MPLS_EOS,
474  .frp_sw_if_index = ~0,
475  .frp_fib_index = 0,
476  .frp_weight = 1,
477  .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
478  .frp_label_stack = 0
479  };
480  fib_route_path_t *paths = NULL;
481 
482  if (steer_pl->vpn_label != (u32) ~ 0)
483  vec_add1 (path.frp_label_stack, steer_pl->vpn_label);
484 
485  /* FIB API calls - Recursive route through the BindingSID */
486  if (traffic_type == SR_STEER_IPV6)
487  {
489  pfx.fp_len = steer_pl->classify.mask_width;
490  pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
491  path.frp_fib_index = 0;
492  path.frp_preference = 0;
493  vec_add1 (paths, path);
496  (table_id != (u32) ~ 0 ? table_id : 0)),
497  &pfx, FIB_SOURCE_SR,
499  vec_free (paths);
500  }
501  else if (traffic_type == SR_STEER_IPV4)
502  {
504  pfx.fp_len = steer_pl->classify.mask_width;
505  pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
506  path.frp_fib_index = 0;
507  path.frp_preference = 0;
508  vec_add1 (paths, path);
511  (table_id != (u32) ~ 0 ? table_id : 0)),
512  &pfx, FIB_SOURCE_SR,
514  vec_free (paths);
515  }
516  }
517  /* Automated steering */
518  else
519  {
520  steer_pl->bsid = (u32) ~ 0;
521  vec_add1 (steer_pl->color, color);
523  internal_label_lock_co (steer_pl->next_hop, color, steer_pl->co_bits);
524  }
525  return 0;
526 }
527 
528 /**
529  * @brief Delete steering rule for an SR-MPLS policy
530  *
531  * @param is_del
532  * @param bsid is the bindingSID of the SR Policy (alt to sr_policy_index)
533  * @param sr_policy is the index of the SR Policy (alt to bsid)
534  * @param table_id is the VRF where to install the FIB entry for the BSID
535  * @param prefix is the IPv4/v6 address for L3 traffic type
536  * @param mask_width is the mask for L3 traffic type
537  * @param traffic_type describes the type of traffic
538  * @param next_hop SR TE Next-HOP
539  * @param nh_type is the AF of Next-Hop
540  * @param color SR TE color
541  *
542  * @return 0 if correct, else error
543  */
544 int
545 sr_mpls_steering_policy_del (ip46_address_t * prefix, u32 mask_width,
546  u8 traffic_type, u32 table_id, u32 color)
547 {
550  mpls_sr_steering_policy_t *steer_pl;
551  fib_prefix_t pfx = { 0 };
552  uword *p = 0;
553 
554  memset (&key, 0, sizeof (sr_mpls_steering_key_t));
555 
556  /* Compute the steer policy key */
557  if (traffic_type != SR_STEER_IPV4 && traffic_type != SR_STEER_IPV6)
558  return -1;
559 
560  key.prefix.as_u64[0] = prefix->as_u64[0];
561  key.prefix.as_u64[1] = prefix->as_u64[1];
562  key.mask_width = mask_width;
563  key.fib_table = (table_id != (u32) ~ 0 ? table_id : 0);
564  key.traffic_type = traffic_type;
565 
566  if (!sm->sr_steer_policies_hash.hash)
567  mhash_init (&sm->sr_steer_policies_hash, sizeof (uword),
568  sizeof (sr_mpls_steering_key_t));
569 
570  /* Search for the item */
571  p = mhash_get (&sm->sr_steer_policies_hash, &key);
572 
573  if (!p)
574  return -1;
575 
576  /* Retrieve Steer Policy function */
577  steer_pl = pool_elt_at_index (sm->steer_policies, p[0]);
578 
579  if (steer_pl->bsid == (u32) ~ 0)
580  {
581  /* Remove the color from the color vector */
582  vec_del1 (steer_pl->color, vec_search (steer_pl->color, color));
583 
584  if (vec_len (steer_pl->color))
585  {
586  /* Reorder Colors */
589  /* Remove all the locks for this ones... */
590  internal_label_unlock_co (steer_pl->next_hop, color,
591  steer_pl->co_bits);
592  return 0;
593  }
594  else
595  {
596  vec_free (steer_pl->color);
597  /* Remove FIB entry */
598  if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
599  {
601  pfx.fp_len = steer_pl->classify.mask_width;
602  pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
605  steer_pl->classify.fib_table), &pfx,
606  FIB_SOURCE_SR);
607  }
608  else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
609  {
611  pfx.fp_len = steer_pl->classify.mask_width;
612  pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
615  steer_pl->classify.fib_table), &pfx,
616  FIB_SOURCE_SR);
617  }
618  /* Remove all the locks for this ones... */
619  internal_label_unlock_co (steer_pl->next_hop, color,
620  steer_pl->co_bits);
621  }
622  }
623  else //Remove by BSID
624  {
625  if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
626  {
628  pfx.fp_len = steer_pl->classify.mask_width;
629  pfx.fp_addr.ip6 = steer_pl->classify.prefix.ip6;
632  steer_pl->classify.fib_table), &pfx,
633  FIB_SOURCE_SR);
634  }
635  else if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
636  {
638  pfx.fp_len = steer_pl->classify.mask_width;
639  pfx.fp_addr.ip4 = steer_pl->classify.prefix.ip4;
642  steer_pl->classify.fib_table), &pfx,
643  FIB_SOURCE_SR);
644  }
645  }
646  /* Delete SR steering policy entry */
647  pool_put (sm->steer_policies, steer_pl);
649  if (mhash_elts (&sm->sr_steer_policies_hash) == 0)
650  {
653  }
654  return 0;
655 }
656 
657 static clib_error_t *
659  vlib_cli_command_t * cmd)
660 {
661  int is_del = 0;
662 
663  ip46_address_t prefix, nh;
664  u32 dst_mask_width = 0;
665  u8 traffic_type = 0;
666  u8 nh_type = 0;
667  u32 fib_table = (u32) ~ 0, color = (u32) ~ 0;
668  u32 co_bits = 0;
669 
670  mpls_label_t bsid, vpn_label = (u32) ~ 0;
671 
672  u8 sr_policy_set = 0;
673 
674  memset (&prefix, 0, sizeof (ip46_address_t));
675  memset (&nh, 0, sizeof (ip46_address_t));
676 
677  int rv;
679  {
680  if (unformat (input, "del"))
681  is_del = 1;
682  else if (!traffic_type
683  && unformat (input, "l3 %U/%d", unformat_ip6_address,
684  &prefix.ip6, &dst_mask_width))
685  traffic_type = SR_STEER_IPV6;
686  else if (!traffic_type
687  && unformat (input, "l3 %U/%d", unformat_ip4_address,
688  &prefix.ip4, &dst_mask_width))
689  traffic_type = SR_STEER_IPV4;
690  else if (!sr_policy_set
691  && unformat (input, "via sr policy bsid %U",
693  sr_policy_set = 1;
694  else if (!sr_policy_set
695  && unformat (input, "via next-hop %U color %d co %d",
696  unformat_ip4_address, &nh.ip4, &color, &co_bits))
697  {
698  sr_policy_set = 1;
699  nh_type = SR_STEER_IPV4;
700  }
701  else if (!sr_policy_set
702  && unformat (input, "via next-hop %U color %d co %d",
703  unformat_ip6_address, &nh.ip6, &color, &co_bits))
704  {
705  sr_policy_set = 1;
706  nh_type = SR_STEER_IPV6;
707  }
708  else if (fib_table == (u32) ~ 0
709  && unformat (input, "fib-table %d", &fib_table));
710  else if (unformat (input, "vpn-label %U",
711  unformat_mpls_unicast_label, &vpn_label));
712  else
713  break;
714  }
715 
716  if (!traffic_type)
717  return clib_error_return (0, "No L3 traffic specified");
718  if (!sr_policy_set)
719  return clib_error_return (0, "No SR policy specified");
720 
721  /* Make sure that the prefixes are clean */
722  if (traffic_type == SR_STEER_IPV4)
723  {
724  u32 mask =
725  (dst_mask_width ? (0xFFFFFFFFu >> (32 - dst_mask_width)) : 0);
726  prefix.ip4.as_u32 &= mask;
727  }
728  else if (traffic_type == SR_STEER_IPV6)
729  {
730  ip6_address_t mask;
731  ip6_address_mask_from_width (&mask, dst_mask_width);
732  ip6_address_mask (&prefix.ip6, &mask);
733  }
734 
735  if (nh_type)
736  bsid = (u32) ~ 0;
737 
738  if (is_del)
739  rv =
740  sr_mpls_steering_policy_del (&prefix, dst_mask_width,
741  traffic_type, fib_table, color);
742 
743  else
744  rv =
745  sr_mpls_steering_policy_add (bsid, fib_table, &prefix, dst_mask_width,
746  traffic_type, &nh, nh_type, color, co_bits,
747  vpn_label);
748 
749  switch (rv)
750  {
751  case 0:
752  break;
753  case 1:
754  return 0;
755  case -1:
756  return clib_error_return (0, "Incorrect API usage.");
757  case -2:
758  return clib_error_return (0, "The Next-Hop does not match.");
759  case -3:
760  return clib_error_return (0, "The color already exists.");
761  case -4:
762  return clib_error_return (0, "The co-bits do not match.");
763  case -5:
764  return clib_error_return (0, "The VPN-labels do not match.");
765  default:
766  return clib_error_return (0, "BUG: sr steer policy returns %d", rv);
767  }
768  return 0;
769 }
770 
771 /* *INDENT-OFF* */
772 VLIB_CLI_COMMAND(sr_mpls_steer_policy_command, static)=
773 {
774  .path = "sr mpls steer",
775  .short_help = "sr mpls steer (del) l3 <ip_addr/mask> "
776  "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)",
777  .long_help =
778  "\tSteer L3 traffic through an existing SR policy.\n"
779  "\tExamples:\n"
780  "\t\tsr steer l3 2001::/64 via sr_policy bsid 29999\n"
781  "\t\tsr steer del l3 2001::/64 via sr_policy bsid 29999\n"
782  "\t\tsr steer l3 2001::/64 via next-hop 1.1.1.1 color 1234 co 0\n"
783  "\t\tsr steer l3 2001::/64 via next-hop 2001::1 color 1234 co 2 vpn-label 500\n",
785 };
786 /* *INDENT-ON* */
787 
788 static clib_error_t *
790  unformat_input_t * input,
791  vlib_cli_command_t * cmd)
792 {
794  mpls_sr_steering_policy_t **steer_policies = 0;
795  mpls_sr_steering_policy_t *steer_pl;
796 
797  int i;
798 
799  vlib_cli_output (vm, "SR MPLS steering policies:");
800  /* *INDENT-OFF* */
801  pool_foreach(steer_pl, sm->steer_policies, ({
802  vec_add1(steer_policies, steer_pl);
803  }));
804  /* *INDENT-ON* */
805  for (i = 0; i < vec_len (steer_policies); i++)
806  {
807  vlib_cli_output (vm, "==========================");
808  steer_pl = steer_policies[i];
809  if (steer_pl->classify.traffic_type == SR_STEER_IPV4)
810  {
811  vlib_cli_output (vm, "Prefix: %U/%d via:",
813  &steer_pl->classify.prefix.ip4,
814  steer_pl->classify.mask_width);
815  }
816  else if (steer_pl->classify.traffic_type == SR_STEER_IPV6)
817  {
818  vlib_cli_output (vm, "Prefix: %U/%d via:",
820  &steer_pl->classify.prefix.ip6,
821  steer_pl->classify.mask_width);
822  }
823 
824  if (steer_pl->bsid != (u32) ~ 0)
825  {
826  vlib_cli_output (vm, "· BSID %U",
827  format_mpls_unicast_label, steer_pl->bsid);
828  }
829  else
830  {
831  if (steer_pl->nh_type == SR_STEER_IPV4)
832  {
833  vlib_cli_output (vm, "· Next-hop %U",
834  format_ip4_address, &steer_pl->next_hop.ip4);
835  }
836  else if (steer_pl->nh_type == SR_STEER_IPV6)
837  {
838  vlib_cli_output (vm, "· Next-hop %U",
839  format_ip6_address, &steer_pl->next_hop.ip6);
840  }
841 
842  u32 *color_i = 0;
843  u8 *s = NULL;
844  s = format (s, "[ ");
845  vec_foreach (color_i, steer_pl->color)
846  {
847  s = format (s, "%d, ", *color_i);
848  }
849  s = format (s, "\b\b ]");
850  vlib_cli_output (vm, "· Color %s", s);
851 
852  switch (steer_pl->co_bits)
853  {
854  case SR_TE_CO_BITS_00:
855  vlib_cli_output (vm, "· CO-bits: 00");
856  break;
857  case SR_TE_CO_BITS_01:
858  vlib_cli_output (vm, "· CO-bits: 01");
859  break;
860  case SR_TE_CO_BITS_10:
861  vlib_cli_output (vm, "· CO-bits: 10");
862  break;
863  case SR_TE_CO_BITS_11:
864  vlib_cli_output (vm, "· CO-bits: 11");
865  break;
866  }
867  }
868  }
869  return 0;
870 }
871 
872 /* *INDENT-OFF* */
873 VLIB_CLI_COMMAND(show_sr_mpls_steering_policies_command, static)=
874 {
875  .path = "show sr mpls steering policies",
876  .short_help = "show sr mpls steering policies",
878 };
879 /* *INDENT-ON* */
880 
881 clib_error_t *
883 {
885 
886  /* Init memory for function keys */
888 
889  sm->fib_table_EC = (u32) ~ 0;
890  sm->ec_labels = 0;
891 
892  return 0;
893 }
894 
895 /* *INDENT-OFF* */
897 /* *INDENT-ON* */
898 
899 /*
900  * fd.io coding-style-patch-verification: ON
901  *
902  * Local Variables: eval: (c-set-style "gnu") End:
903  */
static void ip6_address_mask(ip6_address_t *a, ip6_address_t *mask)
Definition: ip6_packet.h:235
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:181
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:393
#define SR_STEER_IPV6
Definition: sr_mpls.h:42
u8 traffic_type
Traffic type (IPv4, IPv6, L2)
Definition: sr_mpls.h:88
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
#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:404
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:377
ip46_address_t next_hop
SR TE NH.
Definition: sr_mpls.h:96
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
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:706
#define NULL
Definition: clib.h:55
uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:353
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 *rpath)
Add n paths to an entry (aka route) in the FIB.
Definition: fib_table.c:539
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:24
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:518
mhash_t sr_steer_policies_hash
Definition: sr_mpls.h:121
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
dpo_proto_t frp_proto
The protocol of the address below.
Definition: fib_types.h:382
add_epi add_epi sub_epi sub_epi adds_epu subs_epu i16x8 y
Definition: vector_sse2.h:293
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:225
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:80
u32 fib_table
VRF of the prefix.
Definition: sr_mpls.h:87
unformat_function_t unformat_mpls_unicast_label
Definition: mpls.h:79
Definition: fib_entry.h:245
format_function_t format_ip4_address
Definition: format.h:79
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:438
unformat_function_t unformat_ip4_address
Definition: format.h:76
mpls_label_t * frp_label_stack
The outgoing MPLS label Stack.
Definition: fib_types.h:432
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:111
#define always_inline
Definition: clib.h:92
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:1278
Aggregrate type for a prefix.
Definition: fib_types.h:172
#define clib_error_return(e, args...)
Definition: error.h:99
unsigned long u64
Definition: types.h:89
#define vec_search(v, E)
Search a vector for the index of the entry that matches.
Definition: vec.h:937
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:1028
u16 fp_len
The mask length.
Definition: fib_types.h:176
#define SRMPLS_TE_OFFSET
#define hash_get(h, key)
Definition: hash.h:248
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:459
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:195
uword mhash_set_mem(mhash_t *h, void *key, uword *new_value, uword *old_value)
Definition: mhash.c:271
struct _unformat_input_t unformat_input_t
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:271
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:801
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:1180
mpls_label_t bsid
BindingSID (key)
Definition: sr_mpls.h:66
word any
Definition: types.h:139
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:94
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:143
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:95
vlib_main_t * vm
Definition: buffer.c:283
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:229
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:336
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:836
#define clib_memcpy(a, b, c)
Definition: string.h:75
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:154
#define hash_create(elts, value_bytes)
Definition: hash.h:681
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
unsigned int u32
Definition: types.h:88
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:465
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
format_function_t format_mpls_unicast_label
Definition: mpls.h:69
u64 uword
Definition: types.h:112
mpls_label_t frp_local_label
The MPLS local Label to reursively resolve through.
Definition: fib_types.h:400
#define ip46_address_reset(ip46)
Definition: ip6_packet.h:79
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:58
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:956
char co_bits
Color-Only bits.
Definition: sr_mpls.h:99
Segment Routing MPLS data structures definitions.
Special sources.
Definition: fib_entry.h:40
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:251
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 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:1106
u32 frp_fib_index
The FIB index to lookup the nexthop Only valid for recursive paths.
Definition: fib_types.h:423
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:680
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169