FD.io VPP  v17.04-9-g99c0734
Vector Packet Processing
sr_policy_rewrite.c
Go to the documentation of this file.
1 /*
2  * sr_policy_rewrite.c: ipv6 sr policy creation
3  *
4  * Copyright (c) 2016 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /**
19  * @file
20  * @brief SR policy creation and application
21  *
22  * Create an SR policy.
23  * An SR policy can be either of 'default' type or 'spray' type
24  * An SR policy has attached a list of SID lists.
25  * In case the SR policy is a default one it will load balance among them.
26  * An SR policy has associated a BindingSID.
27  * In case any packet arrives with IPv6 DA == BindingSID then the SR policy
28  * associated to such bindingSID will be applied to such packet.
29  *
30  * SR policies can be applied either by using IPv6 encapsulation or
31  * SRH insertion. Both methods can be found on this file.
32  *
33  * Traffic input usually is IPv6 packets. However it is possible to have
34  * IPv4 packets or L2 frames. (that are encapsulated into IPv6 with SRH)
35  *
36  * This file provides the appropiates VPP graph nodes to do any of these
37  * methods.
38  *
39  */
40 
41 #include <vlib/vlib.h>
42 #include <vnet/vnet.h>
43 #include <vnet/sr/sr.h>
44 #include <vnet/ip/ip.h>
45 #include <vnet/sr/sr_packet.h>
46 #include <vnet/ip/ip6_packet.h>
47 #include <vnet/fib/ip6_fib.h>
48 #include <vnet/dpo/dpo.h>
49 #include <vnet/dpo/replicate_dpo.h>
50 
51 #include <vppinfra/error.h>
52 #include <vppinfra/elog.h>
53 
54 /**
55  * @brief SR policy rewrite trace
56  */
57 typedef struct
58 {
61 
62 /* Graph arcs */
63 #define foreach_sr_policy_rewrite_next \
64 _(IP6_LOOKUP, "ip6-lookup") \
65 _(ERROR, "error-drop")
66 
67 typedef enum
68 {
69 #define _(s,n) SR_POLICY_REWRITE_NEXT_##s,
71 #undef _
74 
75 /* SR rewrite errors */
76 #define foreach_sr_policy_rewrite_error \
77 _(INTERNAL_ERROR, "Segment Routing undefined error") \
78 _(BSID_ZERO, "BSID with SL = 0") \
79 _(COUNTER_TOTAL, "SR steered IPv6 packets") \
80 _(COUNTER_ENCAP, "SR: Encaps packets") \
81 _(COUNTER_INSERT, "SR: SRH inserted packets") \
82 _(COUNTER_BSID, "SR: BindingSID steered packets")
83 
84 typedef enum
85 {
86 #define _(sym,str) SR_POLICY_REWRITE_ERROR_##sym,
88 #undef _
91 
93 #define _(sym,string) string,
95 #undef _
96 };
97 
98 /**
99  * @brief Dynamically added SR SL DPO type
100  */
105 
106 /**
107  * @brief IPv6 SA for encapsulated packets
108  */
110 
111 /******************* SR rewrite set encaps IPv6 source addr *******************/
112 /* Note: This is temporal. We don't know whether to follow this path or
113  take the ip address of a loopback interface or even the OIF */
114 
115 static clib_error_t *
117  vlib_cli_command_t * cmd)
118 {
120  {
121  if (unformat
122  (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
123  return 0;
124  else
125  return clib_error_return (0, "No address specified");
126  }
127  return clib_error_return (0, "No address specified");
128 }
129 
130 /* *INDENT-OFF* */
131 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
132  .path = "set sr encaps source",
133  .short_help = "set sr encaps source addr <ip6_addr>",
134  .function = set_sr_src_command_fn,
135 };
136 /* *INDENT-ON* */
137 
138 /*********************** SR rewrite string computation ************************/
139 /**
140  * @brief SR rewrite string computation for IPv6 encapsulation (inline)
141  *
142  * @param sl is a vector of IPv6 addresses composing the Segment List
143  *
144  * @return precomputed rewrite string for encapsulation
145  */
146 static inline u8 *
148 {
149  ip6_header_t *iph;
150  ip6_sr_header_t *srh;
151  ip6_address_t *addrp, *this_address;
152  u32 header_length = 0;
153  u8 *rs = NULL;
154 
155  header_length = 0;
156  header_length += IPv6_DEFAULT_HEADER_LENGTH;
157  if (vec_len (sl) > 1)
158  {
159  header_length += sizeof (ip6_sr_header_t);
160  header_length += vec_len (sl) * sizeof (ip6_address_t);
161  }
162 
163  vec_validate (rs, header_length - 1);
164 
165  iph = (ip6_header_t *) rs;
167  clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
168  iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
169  iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
170  iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
171  iph->protocol = IP_PROTOCOL_IPV6;
173 
174  srh = (ip6_sr_header_t *) (iph + 1);
175  iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
176  srh->protocol = IP_PROTOCOL_IPV6;
178  srh->segments_left = vec_len (sl) - 1;
179  srh->first_segment = vec_len (sl) - 1;
180  srh->length = ((sizeof (ip6_sr_header_t) +
181  (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
182  srh->flags = 0x00;
183  srh->reserved = 0x00;
184  addrp = srh->segments + vec_len (sl) - 1;
185  vec_foreach (this_address, sl)
186  {
187  clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
188  addrp--;
189  }
190  iph->dst_address.as_u64[0] = sl->as_u64[0];
191  iph->dst_address.as_u64[1] = sl->as_u64[1];
192  return rs;
193 }
194 
195 /**
196  * @brief SR rewrite string computation for SRH insertion (inline)
197  *
198  * @param sl is a vector of IPv6 addresses composing the Segment List
199  *
200  * @return precomputed rewrite string for SRH insertion
201  */
202 static inline u8 *
204 {
205  ip6_sr_header_t *srh;
206  ip6_address_t *addrp, *this_address;
207  u32 header_length = 0;
208  u8 *rs = NULL;
209 
210  header_length = 0;
211  header_length += sizeof (ip6_sr_header_t);
212  header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
213 
214  vec_validate (rs, header_length - 1);
215 
216  srh = (ip6_sr_header_t *) rs;
218  srh->segments_left = vec_len (sl);
219  srh->first_segment = vec_len (sl);
220  srh->length = ((sizeof (ip6_sr_header_t) +
221  ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
222  srh->flags = 0x00;
223  srh->reserved = 0x0000;
224  addrp = srh->segments + vec_len (sl);
225  vec_foreach (this_address, sl)
226  {
227  clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
228  addrp--;
229  }
230  return rs;
231 }
232 
233 /**
234  * @brief SR rewrite string computation for SRH insertion with BSID (inline)
235  *
236  * @param sl is a vector of IPv6 addresses composing the Segment List
237  *
238  * @return precomputed rewrite string for SRH insertion with BSID
239  */
240 static inline u8 *
242 {
243  ip6_sr_header_t *srh;
244  ip6_address_t *addrp, *this_address;
245  u32 header_length = 0;
246  u8 *rs = NULL;
247 
248  header_length = 0;
249  header_length += sizeof (ip6_sr_header_t);
250  header_length += vec_len (sl) * sizeof (ip6_address_t);
251 
252  vec_validate (rs, header_length - 1);
253 
254  srh = (ip6_sr_header_t *) rs;
256  srh->segments_left = vec_len (sl) - 1;
257  srh->first_segment = vec_len (sl) - 1;
258  srh->length = ((sizeof (ip6_sr_header_t) +
259  (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
260  srh->flags = 0x00;
261  srh->reserved = 0x0000;
262  addrp = srh->segments + vec_len (sl) - 1;
263  vec_foreach (this_address, sl)
264  {
265  clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
266  addrp--;
267  }
268  return rs;
269 }
270 
271 /*************************** SR LB helper functions **************************/
272 /**
273  * @brief Creates a Segment List and adds it to an SR policy
274  *
275  * Creates a Segment List and adds it to the SR policy. Notice that the SL are
276  * not necessarily unique. Hence there might be two Segment List within the
277  * same SR Policy with exactly the same segments and same weight.
278  *
279  * @param sr_policy is the SR policy where the SL will be added
280  * @param sl is a vector of IPv6 addresses composing the Segment List
281  * @param weight is the weight of the SegmentList (for load-balancing purposes)
282  * @param is_encap represents the mode (SRH insertion vs Encapsulation)
283  *
284  * @return pointer to the just created segment list
285  */
286 static inline ip6_sr_sl_t *
287 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
288  u8 is_encap)
289 {
290  ip6_sr_main_t *sm = &sr_main;
291  ip6_sr_sl_t *segment_list;
292 
293  pool_get (sm->sid_lists, segment_list);
294  memset (segment_list, 0, sizeof (*segment_list));
295 
296  vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
297 
298  /* Fill in segment list */
299  segment_list->weight =
300  (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
301  segment_list->segments = vec_dup (sl);
302 
303  if (is_encap)
304  {
305  segment_list->rewrite = compute_rewrite_encaps (sl);
306  segment_list->rewrite_bsid = segment_list->rewrite;
307  }
308  else
309  {
310  segment_list->rewrite = compute_rewrite_insert (sl);
311  segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
312  }
313 
314  /* Create DPO */
315  dpo_reset (&segment_list->bsid_dpo);
316  dpo_reset (&segment_list->ip6_dpo);
317  dpo_reset (&segment_list->ip4_dpo);
318 
319  if (is_encap)
320  {
322  segment_list - sm->sid_lists);
324  segment_list - sm->sid_lists);
326  DPO_PROTO_IP6, segment_list - sm->sid_lists);
327  }
328  else
329  {
331  segment_list - sm->sid_lists);
333  DPO_PROTO_IP6, segment_list - sm->sid_lists);
334  }
335 
336  return segment_list;
337 }
338 
339 /**
340  * @brief Updates the Load Balancer after an SR Policy change
341  *
342  * @param sr_policy is the modified SR Policy
343  */
344 static inline void
346 {
347  flow_hash_config_t fhc;
348  u32 *sl_index;
349  ip6_sr_sl_t *segment_list;
350  ip6_sr_main_t *sm = &sr_main;
351  load_balance_path_t path;
353  load_balance_path_t *ip4_path_vector = 0;
354  load_balance_path_t *ip6_path_vector = 0;
355  load_balance_path_t *b_path_vector = 0;
356 
357  /* In case LB does not exist, create it */
358  if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
359  {
360  fib_prefix_t pfx = {
362  .fp_len = 128,
363  .fp_addr = {
364  .ip6 = sr_policy->bsid,
365  }
366  };
367 
368  /* Add FIB entry for BSID */
369  fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
371 
374 
377 
378  /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
381  sr_policy->fib_table), &pfx,
384  &sr_policy->bsid_dpo);
385 
387  &pfx,
390  &sr_policy->ip6_dpo);
391 
392  if (sr_policy->is_encap)
393  {
396 
398  &pfx,
401  &sr_policy->ip4_dpo);
402  }
403 
404  }
405 
406  /* Create the LB path vector */
407  //path_vector = vec_new(load_balance_path_t, vec_len(sr_policy->segments_lists));
408  vec_foreach (sl_index, sr_policy->segments_lists)
409  {
410  segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
411  path.path_dpo = segment_list->bsid_dpo;
412  path.path_weight = segment_list->weight;
413  vec_add1 (b_path_vector, path);
414  path.path_dpo = segment_list->ip6_dpo;
415  vec_add1 (ip6_path_vector, path);
416  if (sr_policy->is_encap)
417  {
418  path.path_dpo = segment_list->ip4_dpo;
419  vec_add1 (ip4_path_vector, path);
420  }
421  }
422 
423  /* Update LB multipath */
424  load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
426  load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
428  if (sr_policy->is_encap)
429  load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
431 
432  /* Cleanup */
433  vec_free (b_path_vector);
434  vec_free (ip6_path_vector);
435  vec_free (ip4_path_vector);
436 
437 }
438 
439 /**
440  * @brief Updates the Replicate DPO after an SR Policy change
441  *
442  * @param sr_policy is the modified SR Policy (type spray)
443  */
444 static inline void
446 {
447  u32 *sl_index;
448  ip6_sr_sl_t *segment_list;
449  ip6_sr_main_t *sm = &sr_main;
450  load_balance_path_t path;
452  load_balance_path_t *b_path_vector = 0;
453  load_balance_path_t *ip6_path_vector = 0;
454  load_balance_path_t *ip4_path_vector = 0;
455 
456  /* In case LB does not exist, create it */
457  if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
458  {
459  dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
461 
462  dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
464 
465  /* Update FIB entry's DPO to point to SR without LB */
466  fib_prefix_t pfx = {
468  .fp_len = 128,
469  .fp_addr = {
470  .ip6 = sr_policy->bsid,
471  }
472  };
475  sr_policy->fib_table), &pfx,
478  &sr_policy->bsid_dpo);
479 
481  &pfx,
484  &sr_policy->ip6_dpo);
485 
486  if (sr_policy->is_encap)
487  {
490 
492  &pfx,
495  &sr_policy->ip4_dpo);
496  }
497 
498  }
499 
500  /* Create the replicate path vector */
501  path.path_weight = 1;
502  vec_foreach (sl_index, sr_policy->segments_lists)
503  {
504  segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
505  path.path_dpo = segment_list->bsid_dpo;
506  vec_add1 (b_path_vector, path);
507  path.path_dpo = segment_list->ip6_dpo;
508  vec_add1 (ip6_path_vector, path);
509  if (sr_policy->is_encap)
510  {
511  path.path_dpo = segment_list->ip4_dpo;
512  vec_add1 (ip4_path_vector, path);
513  }
514  }
515 
516  /* Update replicate multipath */
517  replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
518  replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
519  if (sr_policy->is_encap)
520  replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
521 }
522 
523 /******************************* SR rewrite API *******************************/
524 /* Three functions for handling sr policies:
525  * -> sr_policy_add
526  * -> sr_policy_del
527  * -> sr_policy_mod
528  * All of them are API. CLI function on sr_policy_command_fn */
529 
530 /**
531  * @brief Create a new SR policy
532  *
533  * @param bsid is the bindingSID of the SR Policy
534  * @param segments is a vector of IPv6 address composing the segment list
535  * @param weight is the weight of the sid list. optional.
536  * @param behavior is the behavior of the SR policy. (default//spray)
537  * @param fib_table is the VRF where to install the FIB entry for the BSID
538  * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
539  *
540  * @return 0 if correct, else error
541  */
542 int
544  u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
545 {
546  ip6_sr_main_t *sm = &sr_main;
547  ip6_sr_policy_t *sr_policy = 0;
548  uword *p;
549 
550  /* Search for existing keys (BSID) */
551  p = mhash_get (&sm->sr_policies_index_hash, bsid);
552  if (p)
553  {
554  /* Add SR policy that already exists; complain */
555  return -12;
556  }
557 
558  /* Search collision in FIB entries */
559  /* Explanation: It might be possible that some other entity has already
560  * created a route for the BSID. This in theory is impossible, but in
561  * practise we could see it. Assert it and scream if needed */
562  fib_prefix_t pfx = {
564  .fp_len = 128,
565  .fp_addr = {
566  .ip6 = *bsid,
567  }
568  };
569 
570  /* Lookup the FIB index associated to the table selected */
572  (fib_table !=
573  (u32) ~ 0 ? fib_table : 0));
574  if (fib_index == ~0)
575  return -13;
576 
577  /* Lookup whether there exists an entry for the BSID */
578  fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
579  if (FIB_NODE_INDEX_INVALID != fei)
580  return -12; //There is an entry for such lookup
581 
582  /* Add an SR policy object */
583  pool_get (sm->sr_policies, sr_policy);
584  memset (sr_policy, 0, sizeof (*sr_policy));
585  clib_memcpy (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
586  sr_policy->type = behavior;
587  sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
588  sr_policy->is_encap = is_encap;
589 
590  /* Copy the key */
591  mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
592  NULL);
593 
594  /* Create a segment list and add the index to the SR policy */
595  create_sl (sr_policy, segments, weight, is_encap);
596 
597  /* If FIB doesnt exist, create them */
598  if (sm->fib_table_ip6 == (u32) ~ 0)
599  {
601  "SRv6 steering of IP6 prefixes through BSIDs");
603  "SRv6 steering of IP4 prefixes through BSIDs");
604  }
605 
606  /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
607  if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
608  update_lb (sr_policy);
609  else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
610  update_replicate (sr_policy);
611  return 0;
612 }
613 
614 /**
615  * @brief Delete a SR policy
616  *
617  * @param bsid is the bindingSID of the SR Policy
618  * @param index is the index of the SR policy
619  *
620  * @return 0 if correct, else error
621  */
622 int
624 {
625  ip6_sr_main_t *sm = &sr_main;
626  ip6_sr_policy_t *sr_policy = 0;
627  ip6_sr_sl_t *segment_list;
628  u32 *sl_index;
629  uword *p;
630 
631  if (bsid)
632  {
633  p = mhash_get (&sm->sr_policies_index_hash, bsid);
634  if (p)
635  sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
636  else
637  return -1;
638  }
639  else
640  {
641  sr_policy = pool_elt_at_index (sm->sr_policies, index);
642  if (!sr_policy)
643  return -1;
644  }
645 
646  /* Remove BindingSID FIB entry */
647  fib_prefix_t pfx = {
649  .fp_len = 128,
650  .fp_addr = {
651  .ip6 = sr_policy->bsid,
652  }
653  ,
654  };
655 
657  (FIB_PROTOCOL_IP6, sr_policy->fib_table),
658  &pfx, FIB_SOURCE_SR);
659 
661 
662  if (sr_policy->is_encap)
664 
665  if (dpo_id_is_valid (&sr_policy->bsid_dpo))
666  {
667  dpo_reset (&sr_policy->bsid_dpo);
668  dpo_reset (&sr_policy->ip4_dpo);
669  dpo_reset (&sr_policy->ip6_dpo);
670  }
671 
672  /* Clean SID Lists */
673  vec_foreach (sl_index, sr_policy->segments_lists)
674  {
675  segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
676  vec_free (segment_list->segments);
677  vec_free (segment_list->rewrite);
678  vec_free (segment_list->rewrite_bsid);
679  pool_put_index (sm->sid_lists, *sl_index);
680  }
681 
682  /* Remove SR policy entry */
683  mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
684  pool_put (sm->sr_policies, sr_policy);
685 
686  /* If FIB empty unlock it */
687  if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
688  {
691  sm->fib_table_ip6 = (u32) ~ 0;
692  sm->fib_table_ip4 = (u32) ~ 0;
693  }
694 
695  return 0;
696 }
697 
698 /**
699  * @brief Modify an existing SR policy
700  *
701  * The possible modifications are adding a new Segment List, modifying an
702  * existing Segment List (modify the weight only) and delete a given
703  * Segment List from the SR Policy.
704  *
705  * @param bsid is the bindingSID of the SR Policy
706  * @param index is the index of the SR policy
707  * @param fib_table is the VRF where to install the FIB entry for the BSID
708  * @param operation is the operation to perform (among the top ones)
709  * @param segments is a vector of IPv6 address composing the segment list
710  * @param sl_index is the index of the Segment List to modify/delete
711  * @param weight is the weight of the sid list. optional.
712  * @param is_encap Mode. Encapsulation or SRH insertion.
713  *
714  * @return 0 if correct, else error
715  */
716 int
717 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
718  u8 operation, ip6_address_t * segments, u32 sl_index,
719  u32 weight)
720 {
721  ip6_sr_main_t *sm = &sr_main;
722  ip6_sr_policy_t *sr_policy = 0;
723  ip6_sr_sl_t *segment_list;
724  u32 *sl_index_iterate;
725  uword *p;
726 
727  if (bsid)
728  {
729  p = mhash_get (&sm->sr_policies_index_hash, bsid);
730  if (p)
731  sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
732  else
733  return -1;
734  }
735  else
736  {
737  sr_policy = pool_elt_at_index (sm->sr_policies, index);
738  if (!sr_policy)
739  return -1;
740  }
741 
742  if (operation == 1) /* Add SR List to an existing SR policy */
743  {
744  /* Create the new SL */
745  segment_list =
746  create_sl (sr_policy, segments, weight, sr_policy->is_encap);
747 
748  /* Create a new LB DPO */
749  if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
750  update_lb (sr_policy);
751  else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
752  update_replicate (sr_policy);
753  }
754  else if (operation == 2) /* Delete SR List from an existing SR policy */
755  {
756  /* Check that currently there are more than one SID list */
757  if (vec_len (sr_policy->segments_lists) == 1)
758  return -21;
759 
760  /* Check that the SR list does exist and is assigned to the sr policy */
761  vec_foreach (sl_index_iterate, sr_policy->segments_lists)
762  if (*sl_index_iterate == sl_index)
763  break;
764 
765  if (*sl_index_iterate != sl_index)
766  return -22;
767 
768  /* Remove the lucky SR list that is being kicked out */
769  segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
770  vec_free (segment_list->segments);
771  vec_free (segment_list->rewrite);
772  vec_free (segment_list->rewrite_bsid);
773  pool_put_index (sm->sid_lists, sl_index);
774  vec_del1 (sr_policy->segments_lists,
775  sl_index_iterate - sr_policy->segments_lists);
776 
777  /* Create a new LB DPO */
778  if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
779  update_lb (sr_policy);
780  else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
781  update_replicate (sr_policy);
782  }
783  else if (operation == 3) /* Modify the weight of an existing SR List */
784  {
785  /* Find the corresponding SL */
786  vec_foreach (sl_index_iterate, sr_policy->segments_lists)
787  if (*sl_index_iterate == sl_index)
788  break;
789 
790  if (*sl_index_iterate != sl_index)
791  return -32;
792 
793  /* Change the weight */
794  segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
795  segment_list->weight = weight;
796 
797  /* Update LB */
798  if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
799  update_lb (sr_policy);
800  }
801  else /* Incorrect op. */
802  return -1;
803 
804  return 0;
805 }
806 
807 /**
808  * @brief CLI for 'sr policies' command family
809  */
810 static clib_error_t *
812  vlib_cli_command_t * cmd)
813 {
814  int rv = -1;
815  char is_del = 0, is_add = 0, is_mod = 0;
816  char policy_set = 0;
817  ip6_address_t bsid, next_address;
818  u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
819  u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
820  ip6_address_t *segments = 0, *this_seg;
821  u8 operation = 0;
822  char is_encap = 1;
823  char is_spray = 0;
824 
826  {
827  if (!is_add && !is_mod && !is_del && unformat (input, "add"))
828  is_add = 1;
829  else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
830  is_del = 1;
831  else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
832  is_mod = 1;
833  else if (!policy_set
834  && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
835  policy_set = 1;
836  else if (!is_add && !policy_set
837  && unformat (input, "index %d", &sr_policy_index))
838  policy_set = 1;
839  else if (unformat (input, "weight %d", &weight));
840  else
841  if (unformat (input, "next %U", unformat_ip6_address, &next_address))
842  {
843  vec_add2 (segments, this_seg, 1);
844  clib_memcpy (this_seg->as_u8, next_address.as_u8,
845  sizeof (*this_seg));
846  }
847  else if (unformat (input, "add sl"))
848  operation = 1;
849  else if (unformat (input, "del sl index %d", &sl_index))
850  operation = 2;
851  else if (unformat (input, "mod sl index %d", &sl_index))
852  operation = 3;
853  else if (fib_table == (u32) ~ 0
854  && unformat (input, "fib-table %d", &fib_table));
855  else if (unformat (input, "encap"))
856  is_encap = 1;
857  else if (unformat (input, "insert"))
858  is_encap = 0;
859  else if (unformat (input, "spray"))
860  is_spray = 1;
861  else
862  break;
863  }
864 
865  if (!is_add && !is_mod && !is_del)
866  return clib_error_return (0, "Incorrect CLI");
867 
868  if (!policy_set)
869  return clib_error_return (0, "No SR policy BSID or index specified");
870 
871  if (is_add)
872  {
873  if (vec_len (segments) == 0)
874  return clib_error_return (0, "No Segment List specified");
875  rv = sr_policy_add (&bsid, segments, weight,
876  (is_spray ? SR_POLICY_TYPE_SPRAY :
877  SR_POLICY_TYPE_DEFAULT), fib_table, is_encap);
878  }
879  else if (is_del)
880  rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
881  sr_policy_index);
882  else if (is_mod)
883  {
884  if (!operation)
885  return clib_error_return (0, "No SL modification specified");
886  if (operation != 1 && sl_index == (u32) ~ 0)
887  return clib_error_return (0, "No Segment List index specified");
888  if (operation == 1 && vec_len (segments) == 0)
889  return clib_error_return (0, "No Segment List specified");
890  if (operation == 3 && weight == (u32) ~ 0)
891  return clib_error_return (0, "No new weight for the SL specified");
892  rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
893  sr_policy_index, fib_table, operation, segments,
894  sl_index, weight);
895  }
896 
897  switch (rv)
898  {
899  case 0:
900  break;
901  case 1:
902  return 0;
903  case -12:
904  return clib_error_return (0,
905  "There is already a FIB entry for the BindingSID address.\n"
906  "The SR policy could not be created.");
907  case -13:
908  return clib_error_return (0, "The specified FIB table does not exist.");
909  case -21:
910  return clib_error_return (0,
911  "The selected SR policy only contains ONE segment list. "
912  "Please remove the SR policy instead");
913  case -22:
914  return clib_error_return (0,
915  "Could not delete the segment list. "
916  "It is not associated with that SR policy.");
917  case -32:
918  return clib_error_return (0,
919  "Could not modify the segment list. "
920  "The given SL is not associated with such SR policy.");
921  default:
922  return clib_error_return (0, "BUG: sr policy returns %d", rv);
923  }
924  return 0;
925 }
926 
927 /* *INDENT-OFF* */
928 VLIB_CLI_COMMAND (sr_policy_command, static) = {
929  .path = "sr policy",
930  .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
931  "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
932  .long_help =
933  "Manipulation of SR policies.\n"
934  "A Segment Routing policy may contain several SID lists. Each SID list has\n"
935  "an associated weight (default 1), which will result in wECMP (uECMP).\n"
936  "Segment Routing policies might be of type encapsulation or srh insertion\n"
937  "Each SR policy will be associated with a unique BindingSID.\n"
938  "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
939  "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
940  "The add command will create a SR policy with its first segment list (sl)\n"
941  "The mod command allows you to add, remove, or modify the existing segment lists\n"
942  "within an SR policy.\n"
943  "The del command allows you to delete a SR policy along with all its associated\n"
944  "SID lists.\n",
945  .function = sr_policy_command_fn,
946 };
947 /* *INDENT-ON* */
948 
949 /**
950  * @brief CLI to display onscreen all the SR policies
951  */
952 static clib_error_t *
954  vlib_cli_command_t * cmd)
955 {
956  ip6_sr_main_t *sm = &sr_main;
957  u32 *sl_index;
958  ip6_sr_sl_t *segment_list = 0;
959  ip6_sr_policy_t *sr_policy = 0;
960  ip6_sr_policy_t **vec_policies = 0;
962  u8 *s;
963  int i = 0;
964 
965  vlib_cli_output (vm, "SR policies:");
966 
967  /* *INDENT-OFF* */
968  pool_foreach (sr_policy, sm->sr_policies,
969  {vec_add1 (vec_policies, sr_policy); } );
970  /* *INDENT-ON* */
971 
972  vec_foreach_index (i, vec_policies)
973  {
974  sr_policy = vec_policies[i];
975  vlib_cli_output (vm, "[%u].-\tBSID: %U",
976  (u32) (sr_policy - sm->sr_policies),
977  format_ip6_address, &sr_policy->bsid);
978  vlib_cli_output (vm, "\tBehavior: %s",
979  (sr_policy->is_encap ? "Encapsulation" :
980  "SRH insertion"));
981  vlib_cli_output (vm, "\tType: %s",
982  (sr_policy->type ==
983  SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
984  vlib_cli_output (vm, "\tFIB table: %u",
985  (sr_policy->fib_table !=
986  (u32) ~ 0 ? sr_policy->fib_table : 0));
987  vlib_cli_output (vm, "\tSegment Lists:");
988  vec_foreach (sl_index, sr_policy->segments_lists)
989  {
990  s = NULL;
991  s = format (s, "\t[%u].- ", *sl_index);
992  segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
993  s = format (s, "< ");
994  vec_foreach (addr, segment_list->segments)
995  {
996  s = format (s, "%U, ", format_ip6_address, addr);
997  }
998  s = format (s, "\b\b > ");
999  s = format (s, "weight: %u", segment_list->weight);
1000  vlib_cli_output (vm, " %s", s);
1001  }
1002  vlib_cli_output (vm, "-----------");
1003  }
1004  return 0;
1005 }
1006 
1007 /* *INDENT-OFF* */
1008 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1009  .path = "show sr policies",
1010  .short_help = "show sr policies",
1011  .function = show_sr_policies_command_fn,
1012 };
1013 /* *INDENT-ON* */
1014 
1015 /*************************** SR rewrite graph node ****************************/
1016 /**
1017  * @brief Trace for the SR Policy Rewrite graph node
1018  */
1019 static u8 *
1020 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1021 {
1022  //TODO
1023  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1024  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1026 
1027  s = format
1028  (s, "SR-policy-rewrite: src %U dst %U",
1030 
1031  return s;
1032 }
1033 
1034 /**
1035  * @brief IPv6 encapsulation processing as per RFC2473
1036  */
1039  vlib_buffer_t * b0,
1040  ip6_header_t * ip0, ip6_header_t * ip0_encap)
1041 {
1042  u32 new_l0;
1043 
1044  ip0_encap->hop_limit -= 1;
1045  new_l0 =
1046  ip0->payload_length + sizeof (ip6_header_t) +
1047  clib_net_to_host_u16 (ip0_encap->payload_length);
1048  ip0->payload_length = clib_host_to_net_u16 (new_l0);
1051 }
1052 
1053 /**
1054  * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1055  */
1056 static uword
1058  vlib_frame_t * from_frame)
1059 {
1060  ip6_sr_main_t *sm = &sr_main;
1061  u32 n_left_from, next_index, *from, *to_next;
1062 
1063  from = vlib_frame_vector_args (from_frame);
1064  n_left_from = from_frame->n_vectors;
1065 
1066  next_index = node->cached_next_index;
1067 
1068  int encap_pkts = 0, bsid_pkts = 0;
1069 
1070  while (n_left_from > 0)
1071  {
1072  u32 n_left_to_next;
1073 
1074  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1075 
1076  /* Quad - Loop */
1077  while (n_left_from >= 8 && n_left_to_next >= 4)
1078  {
1079  u32 bi0, bi1, bi2, bi3;
1080  vlib_buffer_t *b0, *b1, *b2, *b3;
1081  u32 next0, next1, next2, next3;
1082  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1083  ip6_header_t *ip0, *ip1, *ip2, *ip3;
1084  ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1085  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1086 
1087  /* Prefetch next iteration. */
1088  {
1089  vlib_buffer_t *p4, *p5, *p6, *p7;
1090 
1091  p4 = vlib_get_buffer (vm, from[4]);
1092  p5 = vlib_get_buffer (vm, from[5]);
1093  p6 = vlib_get_buffer (vm, from[6]);
1094  p7 = vlib_get_buffer (vm, from[7]);
1095 
1096  /* Prefetch the buffer header and packet for the N+2 loop iteration */
1097  vlib_prefetch_buffer_header (p4, LOAD);
1098  vlib_prefetch_buffer_header (p5, LOAD);
1099  vlib_prefetch_buffer_header (p6, LOAD);
1100  vlib_prefetch_buffer_header (p7, LOAD);
1101 
1106  }
1107 
1108  to_next[0] = bi0 = from[0];
1109  to_next[1] = bi1 = from[1];
1110  to_next[2] = bi2 = from[2];
1111  to_next[3] = bi3 = from[3];
1112  from += 4;
1113  to_next += 4;
1114  n_left_from -= 4;
1115  n_left_to_next -= 4;
1116 
1117  b0 = vlib_get_buffer (vm, bi0);
1118  b1 = vlib_get_buffer (vm, bi1);
1119  b2 = vlib_get_buffer (vm, bi2);
1120  b3 = vlib_get_buffer (vm, bi3);
1121 
1122  sl0 =
1124  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1125  sl1 =
1127  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1128  sl2 =
1130  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1131  sl3 =
1133  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1134 
1136  vec_len (sl0->rewrite));
1138  vec_len (sl1->rewrite));
1140  vec_len (sl2->rewrite));
1142  vec_len (sl3->rewrite));
1143 
1144  ip0_encap = vlib_buffer_get_current (b0);
1145  ip1_encap = vlib_buffer_get_current (b1);
1146  ip2_encap = vlib_buffer_get_current (b2);
1147  ip3_encap = vlib_buffer_get_current (b3);
1148 
1149  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1150  sl0->rewrite, vec_len (sl0->rewrite));
1151  clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1152  sl1->rewrite, vec_len (sl1->rewrite));
1153  clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1154  sl2->rewrite, vec_len (sl2->rewrite));
1155  clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1156  sl3->rewrite, vec_len (sl3->rewrite));
1157 
1158  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1159  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1160  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1161  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1162 
1163  ip0 = vlib_buffer_get_current (b0);
1164  ip1 = vlib_buffer_get_current (b1);
1165  ip2 = vlib_buffer_get_current (b2);
1166  ip3 = vlib_buffer_get_current (b3);
1167 
1168  encaps_processing_v6 (node, b0, ip0, ip0_encap);
1169  encaps_processing_v6 (node, b1, ip1, ip1_encap);
1170  encaps_processing_v6 (node, b2, ip2, ip2_encap);
1171  encaps_processing_v6 (node, b3, ip3, ip3_encap);
1172 
1173  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1174  {
1176  {
1178  vlib_add_trace (vm, node, b0, sizeof (*tr));
1179  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1180  sizeof (tr->src.as_u8));
1181  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1182  sizeof (tr->dst.as_u8));
1183  }
1184 
1186  {
1188  vlib_add_trace (vm, node, b1, sizeof (*tr));
1189  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1190  sizeof (tr->src.as_u8));
1191  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1192  sizeof (tr->dst.as_u8));
1193  }
1194 
1196  {
1198  vlib_add_trace (vm, node, b2, sizeof (*tr));
1199  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1200  sizeof (tr->src.as_u8));
1201  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1202  sizeof (tr->dst.as_u8));
1203  }
1204 
1206  {
1208  vlib_add_trace (vm, node, b3, sizeof (*tr));
1209  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1210  sizeof (tr->src.as_u8));
1211  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1212  sizeof (tr->dst.as_u8));
1213  }
1214  }
1215 
1216  encap_pkts += 4;
1217  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1218  n_left_to_next, bi0, bi1, bi2, bi3,
1219  next0, next1, next2, next3);
1220  }
1221 
1222  /* Single loop for potentially the last three packets */
1223  while (n_left_from > 0 && n_left_to_next > 0)
1224  {
1225  u32 bi0;
1226  vlib_buffer_t *b0;
1227  ip6_header_t *ip0 = 0, *ip0_encap = 0;
1228  ip6_sr_sl_t *sl0;
1229  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1230 
1231  bi0 = from[0];
1232  to_next[0] = bi0;
1233  from += 1;
1234  to_next += 1;
1235  n_left_from -= 1;
1236  n_left_to_next -= 1;
1237  b0 = vlib_get_buffer (vm, bi0);
1238 
1239  sl0 =
1241  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1243  vec_len (sl0->rewrite));
1244 
1245  ip0_encap = vlib_buffer_get_current (b0);
1246 
1247  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1248  sl0->rewrite, vec_len (sl0->rewrite));
1249  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1250 
1251  ip0 = vlib_buffer_get_current (b0);
1252 
1253  encaps_processing_v6 (node, b0, ip0, ip0_encap);
1254 
1255  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1257  {
1259  vlib_add_trace (vm, node, b0, sizeof (*tr));
1260  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1261  sizeof (tr->src.as_u8));
1262  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1263  sizeof (tr->dst.as_u8));
1264  }
1265 
1266  encap_pkts++;
1267  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1268  n_left_to_next, bi0, next0);
1269  }
1270 
1271  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1272  }
1273 
1274  /* Update counters */
1276  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1277  encap_pkts);
1279  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1280  bsid_pkts);
1281 
1282  return from_frame->n_vectors;
1283 }
1284 
1285 /* *INDENT-OFF* */
1287  .function = sr_policy_rewrite_encaps,
1288  .name = "sr-pl-rewrite-encaps",
1289  .vector_size = sizeof (u32),
1290  .format_trace = format_sr_policy_rewrite_trace,
1291  .type = VLIB_NODE_TYPE_INTERNAL,
1292  .n_errors = SR_POLICY_REWRITE_N_ERROR,
1293  .error_strings = sr_policy_rewrite_error_strings,
1294  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1295  .next_nodes = {
1296 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1298 #undef _
1299  },
1300 };
1301 /* *INDENT-ON* */
1302 
1303 /**
1304  * @brief IPv4 encapsulation processing as per RFC2473
1305  */
1308  vlib_buffer_t * b0,
1309  ip6_header_t * ip0, ip4_header_t * ip0_encap)
1310 {
1311  u32 new_l0;
1312  ip6_sr_header_t *sr0;
1313 
1314  u32 checksum0;
1315 
1316  /* Inner IPv4: Decrement TTL & update checksum */
1317  ip0_encap->ttl -= 1;
1318  checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1319  checksum0 += checksum0 >= 0xffff;
1320  ip0_encap->checksum = checksum0;
1321 
1322  /* Outer IPv6: Update length, FL, proto */
1323  new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1324  ip0->payload_length = clib_host_to_net_u16 (new_l0);
1326  clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1327  ((ip0_encap->tos & 0xFF) << 20));
1328  sr0 = (void *) (ip0 + 1);
1329  sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1330 }
1331 
1332 /**
1333  * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1334  */
1335 static uword
1337  vlib_frame_t * from_frame)
1338 {
1339  ip6_sr_main_t *sm = &sr_main;
1340  u32 n_left_from, next_index, *from, *to_next;
1341 
1342  from = vlib_frame_vector_args (from_frame);
1343  n_left_from = from_frame->n_vectors;
1344 
1345  next_index = node->cached_next_index;
1346 
1347  int encap_pkts = 0, bsid_pkts = 0;
1348 
1349  while (n_left_from > 0)
1350  {
1351  u32 n_left_to_next;
1352 
1353  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1354 
1355  /* Quad - Loop */
1356  while (n_left_from >= 8 && n_left_to_next >= 4)
1357  {
1358  u32 bi0, bi1, bi2, bi3;
1359  vlib_buffer_t *b0, *b1, *b2, *b3;
1360  u32 next0, next1, next2, next3;
1361  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1362  ip6_header_t *ip0, *ip1, *ip2, *ip3;
1363  ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1364  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1365 
1366  /* Prefetch next iteration. */
1367  {
1368  vlib_buffer_t *p4, *p5, *p6, *p7;
1369 
1370  p4 = vlib_get_buffer (vm, from[4]);
1371  p5 = vlib_get_buffer (vm, from[5]);
1372  p6 = vlib_get_buffer (vm, from[6]);
1373  p7 = vlib_get_buffer (vm, from[7]);
1374 
1375  /* Prefetch the buffer header and packet for the N+2 loop iteration */
1376  vlib_prefetch_buffer_header (p4, LOAD);
1377  vlib_prefetch_buffer_header (p5, LOAD);
1378  vlib_prefetch_buffer_header (p6, LOAD);
1379  vlib_prefetch_buffer_header (p7, LOAD);
1380 
1385  }
1386 
1387  to_next[0] = bi0 = from[0];
1388  to_next[1] = bi1 = from[1];
1389  to_next[2] = bi2 = from[2];
1390  to_next[3] = bi3 = from[3];
1391  from += 4;
1392  to_next += 4;
1393  n_left_from -= 4;
1394  n_left_to_next -= 4;
1395 
1396  b0 = vlib_get_buffer (vm, bi0);
1397  b1 = vlib_get_buffer (vm, bi1);
1398  b2 = vlib_get_buffer (vm, bi2);
1399  b3 = vlib_get_buffer (vm, bi3);
1400 
1401  sl0 =
1403  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1404  sl1 =
1406  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1407  sl2 =
1409  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1410  sl3 =
1412  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1414  vec_len (sl0->rewrite));
1416  vec_len (sl1->rewrite));
1418  vec_len (sl2->rewrite));
1420  vec_len (sl3->rewrite));
1421 
1422  ip0_encap = vlib_buffer_get_current (b0);
1423  ip1_encap = vlib_buffer_get_current (b1);
1424  ip2_encap = vlib_buffer_get_current (b2);
1425  ip3_encap = vlib_buffer_get_current (b3);
1426 
1427  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1428  sl0->rewrite, vec_len (sl0->rewrite));
1429  clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1430  sl1->rewrite, vec_len (sl1->rewrite));
1431  clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1432  sl2->rewrite, vec_len (sl2->rewrite));
1433  clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1434  sl3->rewrite, vec_len (sl3->rewrite));
1435 
1436  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1437  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1438  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1439  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1440 
1441  ip0 = vlib_buffer_get_current (b0);
1442  ip1 = vlib_buffer_get_current (b1);
1443  ip2 = vlib_buffer_get_current (b2);
1444  ip3 = vlib_buffer_get_current (b3);
1445 
1446  encaps_processing_v4 (node, b0, ip0, ip0_encap);
1447  encaps_processing_v4 (node, b1, ip1, ip1_encap);
1448  encaps_processing_v4 (node, b2, ip2, ip2_encap);
1449  encaps_processing_v4 (node, b3, ip3, ip3_encap);
1450 
1451  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1452  {
1454  {
1456  vlib_add_trace (vm, node, b0, sizeof (*tr));
1457  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1458  sizeof (tr->src.as_u8));
1459  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1460  sizeof (tr->dst.as_u8));
1461  }
1462 
1464  {
1466  vlib_add_trace (vm, node, b1, sizeof (*tr));
1467  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1468  sizeof (tr->src.as_u8));
1469  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1470  sizeof (tr->dst.as_u8));
1471  }
1472 
1474  {
1476  vlib_add_trace (vm, node, b2, sizeof (*tr));
1477  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1478  sizeof (tr->src.as_u8));
1479  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1480  sizeof (tr->dst.as_u8));
1481  }
1482 
1484  {
1486  vlib_add_trace (vm, node, b3, sizeof (*tr));
1487  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1488  sizeof (tr->src.as_u8));
1489  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1490  sizeof (tr->dst.as_u8));
1491  }
1492  }
1493 
1494  encap_pkts += 4;
1495  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1496  n_left_to_next, bi0, bi1, bi2, bi3,
1497  next0, next1, next2, next3);
1498  }
1499 
1500  /* Single loop for potentially the last three packets */
1501  while (n_left_from > 0 && n_left_to_next > 0)
1502  {
1503  u32 bi0;
1504  vlib_buffer_t *b0;
1505  ip6_header_t *ip0 = 0;
1506  ip4_header_t *ip0_encap = 0;
1507  ip6_sr_sl_t *sl0;
1508  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1509 
1510  bi0 = from[0];
1511  to_next[0] = bi0;
1512  from += 1;
1513  to_next += 1;
1514  n_left_from -= 1;
1515  n_left_to_next -= 1;
1516  b0 = vlib_get_buffer (vm, bi0);
1517 
1518  sl0 =
1520  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1522  vec_len (sl0->rewrite));
1523 
1524  ip0_encap = vlib_buffer_get_current (b0);
1525 
1526  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1527  sl0->rewrite, vec_len (sl0->rewrite));
1528  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1529 
1530  ip0 = vlib_buffer_get_current (b0);
1531 
1532  encaps_processing_v4 (node, b0, ip0, ip0_encap);
1533 
1534  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1536  {
1538  vlib_add_trace (vm, node, b0, sizeof (*tr));
1539  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1540  sizeof (tr->src.as_u8));
1541  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1542  sizeof (tr->dst.as_u8));
1543  }
1544 
1545  encap_pkts++;
1546  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1547  n_left_to_next, bi0, next0);
1548  }
1549 
1550  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1551  }
1552 
1553  /* Update counters */
1555  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1556  encap_pkts);
1558  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1559  bsid_pkts);
1560 
1561  return from_frame->n_vectors;
1562 }
1563 
1564 /* *INDENT-OFF* */
1566  .function = sr_policy_rewrite_encaps_v4,
1567  .name = "sr-pl-rewrite-encaps-v4",
1568  .vector_size = sizeof (u32),
1569  .format_trace = format_sr_policy_rewrite_trace,
1570  .type = VLIB_NODE_TYPE_INTERNAL,
1571  .n_errors = SR_POLICY_REWRITE_N_ERROR,
1572  .error_strings = sr_policy_rewrite_error_strings,
1573  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1574  .next_nodes = {
1575 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1577 #undef _
1578  },
1579 };
1580 /* *INDENT-ON* */
1581 
1583 ip_flow_hash (void *data)
1584 {
1585  ip4_header_t *iph = (ip4_header_t *) data;
1586 
1587  if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1589  else
1591 }
1592 
1595 {
1596  return (*((u64 *) m) & 0xffffffffffff);
1597 }
1598 
1601 {
1602  ethernet_header_t *eh;
1603  u64 a, b, c;
1604  uword is_ip, eh_size;
1605  u16 eh_type;
1606 
1607  eh = vlib_buffer_get_current (b0);
1608  eh_type = clib_net_to_host_u16 (eh->type);
1609  eh_size = ethernet_buffer_header_size (b0);
1610 
1611  is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1612 
1613  /* since we have 2 cache lines, use them */
1614  if (is_ip)
1615  a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1616  else
1617  a = eh->type;
1618 
1619  b = mac_to_u64 ((u8 *) eh->dst_address);
1620  c = mac_to_u64 ((u8 *) eh->src_address);
1621  hash_mix64 (a, b, c);
1622 
1623  return (u32) c;
1624 }
1625 
1626 /**
1627  * @brief Graph node for applying a SR policy into a L2 frame
1628  */
1629 static uword
1631  vlib_frame_t * from_frame)
1632 {
1633  ip6_sr_main_t *sm = &sr_main;
1634  u32 n_left_from, next_index, *from, *to_next;
1635 
1636  from = vlib_frame_vector_args (from_frame);
1637  n_left_from = from_frame->n_vectors;
1638 
1639  next_index = node->cached_next_index;
1640 
1641  int encap_pkts = 0, bsid_pkts = 0;
1642 
1643  while (n_left_from > 0)
1644  {
1645  u32 n_left_to_next;
1646 
1647  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1648 
1649  /* Quad - Loop */
1650  while (n_left_from >= 8 && n_left_to_next >= 4)
1651  {
1652  u32 bi0, bi1, bi2, bi3;
1653  vlib_buffer_t *b0, *b1, *b2, *b3;
1654  u32 next0, next1, next2, next3;
1655  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1656  ethernet_header_t *en0, *en1, *en2, *en3;
1657  ip6_header_t *ip0, *ip1, *ip2, *ip3;
1658  ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1659  ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1660  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1661 
1662  /* Prefetch next iteration. */
1663  {
1664  vlib_buffer_t *p4, *p5, *p6, *p7;
1665 
1666  p4 = vlib_get_buffer (vm, from[4]);
1667  p5 = vlib_get_buffer (vm, from[5]);
1668  p6 = vlib_get_buffer (vm, from[6]);
1669  p7 = vlib_get_buffer (vm, from[7]);
1670 
1671  /* Prefetch the buffer header and packet for the N+2 loop iteration */
1672  vlib_prefetch_buffer_header (p4, LOAD);
1673  vlib_prefetch_buffer_header (p5, LOAD);
1674  vlib_prefetch_buffer_header (p6, LOAD);
1675  vlib_prefetch_buffer_header (p7, LOAD);
1676 
1681  }
1682 
1683  to_next[0] = bi0 = from[0];
1684  to_next[1] = bi1 = from[1];
1685  to_next[2] = bi2 = from[2];
1686  to_next[3] = bi3 = from[3];
1687  from += 4;
1688  to_next += 4;
1689  n_left_from -= 4;
1690  n_left_to_next -= 4;
1691 
1692  b0 = vlib_get_buffer (vm, bi0);
1693  b1 = vlib_get_buffer (vm, bi1);
1694  b2 = vlib_get_buffer (vm, bi2);
1695  b3 = vlib_get_buffer (vm, bi3);
1696 
1697  sp0 = pool_elt_at_index (sm->sr_policies,
1699  (b0)->sw_if_index
1700  [VLIB_RX]]);
1701 
1702  sp1 = pool_elt_at_index (sm->sr_policies,
1704  (b1)->sw_if_index
1705  [VLIB_RX]]);
1706 
1707  sp2 = pool_elt_at_index (sm->sr_policies,
1709  (b2)->sw_if_index
1710  [VLIB_RX]]);
1711 
1712  sp3 = pool_elt_at_index (sm->sr_policies,
1714  (b3)->sw_if_index
1715  [VLIB_RX]]);
1716 
1717  if (vec_len (sp0->segments_lists) == 1)
1718  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1719  else
1720  {
1721  vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1722  vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1723  sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1724  (vec_len (sp0->segments_lists) - 1))];
1725  }
1726 
1727  if (vec_len (sp1->segments_lists) == 1)
1728  vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1729  else
1730  {
1731  vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1732  vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1733  sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1734  (vec_len (sp1->segments_lists) - 1))];
1735  }
1736 
1737  if (vec_len (sp2->segments_lists) == 1)
1738  vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1739  else
1740  {
1741  vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1742  vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1743  sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1744  (vec_len (sp2->segments_lists) - 1))];
1745  }
1746 
1747  if (vec_len (sp3->segments_lists) == 1)
1748  vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1749  else
1750  {
1751  vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1752  vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1753  sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1754  (vec_len (sp3->segments_lists) - 1))];
1755  }
1756 
1757  sl0 =
1759  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1760  sl1 =
1762  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1763  sl2 =
1765  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1766  sl3 =
1768  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1769 
1771  vec_len (sl0->rewrite));
1773  vec_len (sl1->rewrite));
1775  vec_len (sl2->rewrite));
1777  vec_len (sl3->rewrite));
1778 
1779  en0 = vlib_buffer_get_current (b0);
1780  en1 = vlib_buffer_get_current (b1);
1781  en2 = vlib_buffer_get_current (b2);
1782  en3 = vlib_buffer_get_current (b3);
1783 
1784  clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1785  vec_len (sl0->rewrite));
1786  clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1787  vec_len (sl1->rewrite));
1788  clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1789  vec_len (sl2->rewrite));
1790  clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1791  vec_len (sl3->rewrite));
1792 
1793  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1794  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1795  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1796  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1797 
1798  ip0 = vlib_buffer_get_current (b0);
1799  ip1 = vlib_buffer_get_current (b1);
1800  ip2 = vlib_buffer_get_current (b2);
1801  ip3 = vlib_buffer_get_current (b3);
1802 
1803  ip0->payload_length =
1804  clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1805  ip1->payload_length =
1806  clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1807  ip2->payload_length =
1808  clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1809  ip3->payload_length =
1810  clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1811 
1812  sr0 = (void *) (ip0 + 1);
1813  sr1 = (void *) (ip1 + 1);
1814  sr2 = (void *) (ip2 + 1);
1815  sr3 = (void *) (ip3 + 1);
1816 
1817  sr0->protocol = sr1->protocol = sr2->protocol = sr3->protocol =
1818  IP_PROTOCOL_IP6_NONXT;
1819 
1820  /* Which Traffic class and flow label do I set ? */
1821  //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1822 
1823  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1824  {
1826  {
1828  vlib_add_trace (vm, node, b0, sizeof (*tr));
1829  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1830  sizeof (tr->src.as_u8));
1831  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1832  sizeof (tr->dst.as_u8));
1833  }
1834 
1836  {
1838  vlib_add_trace (vm, node, b1, sizeof (*tr));
1839  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1840  sizeof (tr->src.as_u8));
1841  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1842  sizeof (tr->dst.as_u8));
1843  }
1844 
1846  {
1848  vlib_add_trace (vm, node, b2, sizeof (*tr));
1849  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1850  sizeof (tr->src.as_u8));
1851  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1852  sizeof (tr->dst.as_u8));
1853  }
1854 
1856  {
1858  vlib_add_trace (vm, node, b3, sizeof (*tr));
1859  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1860  sizeof (tr->src.as_u8));
1861  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1862  sizeof (tr->dst.as_u8));
1863  }
1864  }
1865 
1866  encap_pkts += 4;
1867  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1868  n_left_to_next, bi0, bi1, bi2, bi3,
1869  next0, next1, next2, next3);
1870  }
1871 
1872  /* Single loop for potentially the last three packets */
1873  while (n_left_from > 0 && n_left_to_next > 0)
1874  {
1875  u32 bi0;
1876  vlib_buffer_t *b0;
1877  ip6_header_t *ip0 = 0;
1878  ip6_sr_header_t *sr0;
1879  ethernet_header_t *en0;
1880  ip6_sr_policy_t *sp0;
1881  ip6_sr_sl_t *sl0;
1882  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1883 
1884  bi0 = from[0];
1885  to_next[0] = bi0;
1886  from += 1;
1887  to_next += 1;
1888  n_left_from -= 1;
1889  n_left_to_next -= 1;
1890  b0 = vlib_get_buffer (vm, bi0);
1891 
1892  /* Find the SR policy */
1893  sp0 = pool_elt_at_index (sm->sr_policies,
1895  (b0)->sw_if_index
1896  [VLIB_RX]]);
1897 
1898  /* In case there is more than one SL, LB among them */
1899  if (vec_len (sp0->segments_lists) == 1)
1900  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1901  else
1902  {
1903  vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1904  vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1905  sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1906  (vec_len (sp0->segments_lists) - 1))];
1907  }
1908  sl0 =
1910  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1912  vec_len (sl0->rewrite));
1913 
1914  en0 = vlib_buffer_get_current (b0);
1915 
1916  clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1917  vec_len (sl0->rewrite));
1918 
1919  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1920 
1921  ip0 = vlib_buffer_get_current (b0);
1922 
1923  ip0->payload_length =
1924  clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1925 
1926  sr0 = (void *) (ip0 + 1);
1927  sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1928 
1929  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1931  {
1933  vlib_add_trace (vm, node, b0, sizeof (*tr));
1934  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1935  sizeof (tr->src.as_u8));
1936  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1937  sizeof (tr->dst.as_u8));
1938  }
1939 
1940  encap_pkts++;
1941  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1942  n_left_to_next, bi0, next0);
1943  }
1944 
1945  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1946  }
1947 
1948  /* Update counters */
1950  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1951  encap_pkts);
1953  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1954  bsid_pkts);
1955 
1956  return from_frame->n_vectors;
1957 }
1958 
1959 /* *INDENT-OFF* */
1961  .function = sr_policy_rewrite_encaps_l2,
1962  .name = "sr-pl-rewrite-encaps-l2",
1963  .vector_size = sizeof (u32),
1964  .format_trace = format_sr_policy_rewrite_trace,
1965  .type = VLIB_NODE_TYPE_INTERNAL,
1966  .n_errors = SR_POLICY_REWRITE_N_ERROR,
1967  .error_strings = sr_policy_rewrite_error_strings,
1968  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1969  .next_nodes = {
1970 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1972 #undef _
1973  },
1974 };
1975 /* *INDENT-ON* */
1976 
1977 /**
1978  * @brief Graph node for applying a SR policy into a packet. SRH insertion.
1979  */
1980 static uword
1982  vlib_frame_t * from_frame)
1983 {
1984  ip6_sr_main_t *sm = &sr_main;
1985  u32 n_left_from, next_index, *from, *to_next;
1986 
1987  from = vlib_frame_vector_args (from_frame);
1988  n_left_from = from_frame->n_vectors;
1989 
1990  next_index = node->cached_next_index;
1991 
1992  int insert_pkts = 0, bsid_pkts = 0;
1993 
1994  while (n_left_from > 0)
1995  {
1996  u32 n_left_to_next;
1997 
1998  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1999 
2000  /* Quad - Loop */
2001  while (n_left_from >= 8 && n_left_to_next >= 4)
2002  {
2003  u32 bi0, bi1, bi2, bi3;
2004  vlib_buffer_t *b0, *b1, *b2, *b3;
2005  u32 next0, next1, next2, next3;
2006  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2007  ip6_header_t *ip0, *ip1, *ip2, *ip3;
2008  ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2009  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2010  u16 new_l0, new_l1, new_l2, new_l3;
2011 
2012  /* Prefetch next iteration. */
2013  {
2014  vlib_buffer_t *p4, *p5, *p6, *p7;
2015 
2016  p4 = vlib_get_buffer (vm, from[4]);
2017  p5 = vlib_get_buffer (vm, from[5]);
2018  p6 = vlib_get_buffer (vm, from[6]);
2019  p7 = vlib_get_buffer (vm, from[7]);
2020 
2021  /* Prefetch the buffer header and packet for the N+2 loop iteration */
2022  vlib_prefetch_buffer_header (p4, LOAD);
2023  vlib_prefetch_buffer_header (p5, LOAD);
2024  vlib_prefetch_buffer_header (p6, LOAD);
2025  vlib_prefetch_buffer_header (p7, LOAD);
2026 
2031  }
2032 
2033  to_next[0] = bi0 = from[0];
2034  to_next[1] = bi1 = from[1];
2035  to_next[2] = bi2 = from[2];
2036  to_next[3] = bi3 = from[3];
2037  from += 4;
2038  to_next += 4;
2039  n_left_from -= 4;
2040  n_left_to_next -= 4;
2041 
2042  b0 = vlib_get_buffer (vm, bi0);
2043  b1 = vlib_get_buffer (vm, bi1);
2044  b2 = vlib_get_buffer (vm, bi2);
2045  b3 = vlib_get_buffer (vm, bi3);
2046 
2047  sl0 =
2049  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2050  sl1 =
2052  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2053  sl2 =
2055  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2056  sl3 =
2058  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2060  vec_len (sl0->rewrite));
2062  vec_len (sl1->rewrite));
2064  vec_len (sl2->rewrite));
2066  vec_len (sl3->rewrite));
2067 
2068  ip0 = vlib_buffer_get_current (b0);
2069  ip1 = vlib_buffer_get_current (b1);
2070  ip2 = vlib_buffer_get_current (b2);
2071  ip3 = vlib_buffer_get_current (b3);
2072 
2073  if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2074  sr0 =
2075  (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2076  ip6_ext_header_len (ip0 + 1));
2077  else
2078  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2079 
2080  if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2081  sr1 =
2082  (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2083  ip6_ext_header_len (ip1 + 1));
2084  else
2085  sr1 = (ip6_sr_header_t *) (ip1 + 1);
2086 
2087  if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2088  sr2 =
2089  (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2090  ip6_ext_header_len (ip2 + 1));
2091  else
2092  sr2 = (ip6_sr_header_t *) (ip2 + 1);
2093 
2094  if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2095  sr3 =
2096  (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2097  ip6_ext_header_len (ip3 + 1));
2098  else
2099  sr3 = (ip6_sr_header_t *) (ip3 + 1);
2100 
2101  clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2102  (void *) sr0 - (void *) ip0);
2103  clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2104  (void *) sr1 - (void *) ip1);
2105  clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2106  (void *) sr2 - (void *) ip2);
2107  clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2108  (void *) sr3 - (void *) ip3);
2109 
2110  clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2111  vec_len (sl0->rewrite));
2112  clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2113  vec_len (sl1->rewrite));
2114  clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2115  vec_len (sl2->rewrite));
2116  clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2117  vec_len (sl3->rewrite));
2118 
2119  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2120  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2121  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2122  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2123 
2124  ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2125  ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2126  ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2127  ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2128 
2129  ip0->hop_limit -= 1;
2130  ip1->hop_limit -= 1;
2131  ip2->hop_limit -= 1;
2132  ip3->hop_limit -= 1;
2133 
2134  new_l0 =
2135  clib_net_to_host_u16 (ip0->payload_length) +
2136  vec_len (sl0->rewrite);
2137  new_l1 =
2138  clib_net_to_host_u16 (ip1->payload_length) +
2139  vec_len (sl1->rewrite);
2140  new_l2 =
2141  clib_net_to_host_u16 (ip2->payload_length) +
2142  vec_len (sl2->rewrite);
2143  new_l3 =
2144  clib_net_to_host_u16 (ip3->payload_length) +
2145  vec_len (sl3->rewrite);
2146 
2147  ip0->payload_length = clib_host_to_net_u16 (new_l0);
2148  ip1->payload_length = clib_host_to_net_u16 (new_l1);
2149  ip2->payload_length = clib_host_to_net_u16 (new_l2);
2150  ip3->payload_length = clib_host_to_net_u16 (new_l3);
2151 
2152  sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2153  sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2154  sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2155  sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2156 
2157  sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2158  sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2159  sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2160  sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2161  sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2162  sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2163  sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2164  sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2165 
2166  ip0->dst_address.as_u64[0] =
2167  (sr0->segments + sr0->segments_left)->as_u64[0];
2168  ip0->dst_address.as_u64[1] =
2169  (sr0->segments + sr0->segments_left)->as_u64[1];
2170  ip1->dst_address.as_u64[0] =
2171  (sr1->segments + sr1->segments_left)->as_u64[0];
2172  ip1->dst_address.as_u64[1] =
2173  (sr1->segments + sr1->segments_left)->as_u64[1];
2174  ip2->dst_address.as_u64[0] =
2175  (sr2->segments + sr2->segments_left)->as_u64[0];
2176  ip2->dst_address.as_u64[1] =
2177  (sr2->segments + sr2->segments_left)->as_u64[1];
2178  ip3->dst_address.as_u64[0] =
2179  (sr3->segments + sr3->segments_left)->as_u64[0];
2180  ip3->dst_address.as_u64[1] =
2181  (sr3->segments + sr3->segments_left)->as_u64[1];
2182 
2183  ip6_ext_header_t *ip_ext;
2184  if (ip0 + 1 == (void *) sr0)
2185  {
2186  sr0->protocol = ip0->protocol;
2187  ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2188  }
2189  else
2190  {
2191  ip_ext = (void *) (ip0 + 1);
2192  sr0->protocol = ip_ext->next_hdr;
2193  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2194  }
2195 
2196  if (ip1 + 1 == (void *) sr1)
2197  {
2198  sr1->protocol = ip1->protocol;
2199  ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2200  }
2201  else
2202  {
2203  ip_ext = (void *) (ip2 + 1);
2204  sr2->protocol = ip_ext->next_hdr;
2205  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2206  }
2207 
2208  if (ip2 + 1 == (void *) sr2)
2209  {
2210  sr2->protocol = ip2->protocol;
2211  ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2212  }
2213  else
2214  {
2215  ip_ext = (void *) (ip2 + 1);
2216  sr2->protocol = ip_ext->next_hdr;
2217  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2218  }
2219 
2220  if (ip3 + 1 == (void *) sr3)
2221  {
2222  sr3->protocol = ip3->protocol;
2223  ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2224  }
2225  else
2226  {
2227  ip_ext = (void *) (ip3 + 1);
2228  sr3->protocol = ip_ext->next_hdr;
2229  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2230  }
2231 
2232  insert_pkts += 4;
2233 
2234  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2235  {
2237  {
2239  vlib_add_trace (vm, node, b0, sizeof (*tr));
2240  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2241  sizeof (tr->src.as_u8));
2242  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2243  sizeof (tr->dst.as_u8));
2244  }
2245 
2247  {
2249  vlib_add_trace (vm, node, b1, sizeof (*tr));
2250  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2251  sizeof (tr->src.as_u8));
2252  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2253  sizeof (tr->dst.as_u8));
2254  }
2255 
2257  {
2259  vlib_add_trace (vm, node, b2, sizeof (*tr));
2260  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2261  sizeof (tr->src.as_u8));
2262  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2263  sizeof (tr->dst.as_u8));
2264  }
2265 
2267  {
2269  vlib_add_trace (vm, node, b3, sizeof (*tr));
2270  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2271  sizeof (tr->src.as_u8));
2272  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2273  sizeof (tr->dst.as_u8));
2274  }
2275  }
2276 
2277  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2278  n_left_to_next, bi0, bi1, bi2, bi3,
2279  next0, next1, next2, next3);
2280  }
2281 
2282  /* Single loop for potentially the last three packets */
2283  while (n_left_from > 0 && n_left_to_next > 0)
2284  {
2285  u32 bi0;
2286  vlib_buffer_t *b0;
2287  ip6_header_t *ip0 = 0;
2288  ip6_sr_header_t *sr0 = 0;
2289  ip6_sr_sl_t *sl0;
2290  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2291  u16 new_l0 = 0;
2292 
2293  bi0 = from[0];
2294  to_next[0] = bi0;
2295  from += 1;
2296  to_next += 1;
2297  n_left_from -= 1;
2298  n_left_to_next -= 1;
2299 
2300  b0 = vlib_get_buffer (vm, bi0);
2301  sl0 =
2303  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2305  vec_len (sl0->rewrite));
2306 
2307  ip0 = vlib_buffer_get_current (b0);
2308 
2309  if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2310  sr0 =
2311  (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2312  ip6_ext_header_len (ip0 + 1));
2313  else
2314  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2315 
2316  clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2317  (void *) sr0 - (void *) ip0);
2318  clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2319  vec_len (sl0->rewrite));
2320 
2321  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2322 
2323  ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2324  ip0->hop_limit -= 1;
2325  new_l0 =
2326  clib_net_to_host_u16 (ip0->payload_length) +
2327  vec_len (sl0->rewrite);
2328  ip0->payload_length = clib_host_to_net_u16 (new_l0);
2329 
2330  sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2331  sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2332  sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2333 
2334  ip0->dst_address.as_u64[0] =
2335  (sr0->segments + sr0->segments_left)->as_u64[0];
2336  ip0->dst_address.as_u64[1] =
2337  (sr0->segments + sr0->segments_left)->as_u64[1];
2338 
2339  if (ip0 + 1 == (void *) sr0)
2340  {
2341  sr0->protocol = ip0->protocol;
2342  ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2343  }
2344  else
2345  {
2346  ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2347  sr0->protocol = ip_ext->next_hdr;
2348  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2349  }
2350 
2351  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2353  {
2355  vlib_add_trace (vm, node, b0, sizeof (*tr));
2356  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2357  sizeof (tr->src.as_u8));
2358  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2359  sizeof (tr->dst.as_u8));
2360  }
2361 
2362  insert_pkts++;
2363 
2364  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2365  n_left_to_next, bi0, next0);
2366  }
2367 
2368  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2369  }
2370 
2371  /* Update counters */
2373  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2374  insert_pkts);
2376  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2377  bsid_pkts);
2378  return from_frame->n_vectors;
2379 }
2380 
2381 /* *INDENT-OFF* */
2383  .function = sr_policy_rewrite_insert,
2384  .name = "sr-pl-rewrite-insert",
2385  .vector_size = sizeof (u32),
2386  .format_trace = format_sr_policy_rewrite_trace,
2387  .type = VLIB_NODE_TYPE_INTERNAL,
2388  .n_errors = SR_POLICY_REWRITE_N_ERROR,
2389  .error_strings = sr_policy_rewrite_error_strings,
2390  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2391  .next_nodes = {
2392 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2394 #undef _
2395  },
2396 };
2397 /* *INDENT-ON* */
2398 
2399 /**
2400  * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2401  */
2402 static uword
2404  vlib_frame_t * from_frame)
2405 {
2406  ip6_sr_main_t *sm = &sr_main;
2407  u32 n_left_from, next_index, *from, *to_next;
2408 
2409  from = vlib_frame_vector_args (from_frame);
2410  n_left_from = from_frame->n_vectors;
2411 
2412  next_index = node->cached_next_index;
2413 
2414  int insert_pkts = 0, bsid_pkts = 0;
2415 
2416  while (n_left_from > 0)
2417  {
2418  u32 n_left_to_next;
2419 
2420  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2421 
2422  /* Quad - Loop */
2423  while (n_left_from >= 8 && n_left_to_next >= 4)
2424  {
2425  u32 bi0, bi1, bi2, bi3;
2426  vlib_buffer_t *b0, *b1, *b2, *b3;
2427  u32 next0, next1, next2, next3;
2428  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2429  ip6_header_t *ip0, *ip1, *ip2, *ip3;
2430  ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2431  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2432  u16 new_l0, new_l1, new_l2, new_l3;
2433 
2434  /* Prefetch next iteration. */
2435  {
2436  vlib_buffer_t *p4, *p5, *p6, *p7;
2437 
2438  p4 = vlib_get_buffer (vm, from[4]);
2439  p5 = vlib_get_buffer (vm, from[5]);
2440  p6 = vlib_get_buffer (vm, from[6]);
2441  p7 = vlib_get_buffer (vm, from[7]);
2442 
2443  /* Prefetch the buffer header and packet for the N+2 loop iteration */
2444  vlib_prefetch_buffer_header (p4, LOAD);
2445  vlib_prefetch_buffer_header (p5, LOAD);
2446  vlib_prefetch_buffer_header (p6, LOAD);
2447  vlib_prefetch_buffer_header (p7, LOAD);
2448 
2453  }
2454 
2455  to_next[0] = bi0 = from[0];
2456  to_next[1] = bi1 = from[1];
2457  to_next[2] = bi2 = from[2];
2458  to_next[3] = bi3 = from[3];
2459  from += 4;
2460  to_next += 4;
2461  n_left_from -= 4;
2462  n_left_to_next -= 4;
2463 
2464  b0 = vlib_get_buffer (vm, bi0);
2465  b1 = vlib_get_buffer (vm, bi1);
2466  b2 = vlib_get_buffer (vm, bi2);
2467  b3 = vlib_get_buffer (vm, bi3);
2468 
2469  sl0 =
2471  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2472  sl1 =
2474  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2475  sl2 =
2477  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2478  sl3 =
2480  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2482  vec_len (sl0->rewrite_bsid));
2484  vec_len (sl1->rewrite_bsid));
2486  vec_len (sl2->rewrite_bsid));
2488  vec_len (sl3->rewrite_bsid));
2489 
2490  ip0 = vlib_buffer_get_current (b0);
2491  ip1 = vlib_buffer_get_current (b1);
2492  ip2 = vlib_buffer_get_current (b2);
2493  ip3 = vlib_buffer_get_current (b3);
2494 
2495  if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2496  sr0 =
2497  (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2498  ip6_ext_header_len (ip0 + 1));
2499  else
2500  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2501 
2502  if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2503  sr1 =
2504  (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2505  ip6_ext_header_len (ip1 + 1));
2506  else
2507  sr1 = (ip6_sr_header_t *) (ip1 + 1);
2508 
2509  if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2510  sr2 =
2511  (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2512  ip6_ext_header_len (ip2 + 1));
2513  else
2514  sr2 = (ip6_sr_header_t *) (ip2 + 1);
2515 
2516  if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2517  sr3 =
2518  (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2519  ip6_ext_header_len (ip3 + 1));
2520  else
2521  sr3 = (ip6_sr_header_t *) (ip3 + 1);
2522 
2523  clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2524  (void *) sr0 - (void *) ip0);
2525  clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2526  (void *) sr1 - (void *) ip1);
2527  clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2528  (void *) sr2 - (void *) ip2);
2529  clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2530  (void *) sr3 - (void *) ip3);
2531 
2532  clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2533  sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2534  clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2535  sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2536  clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2537  sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2538  clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2539  sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2540 
2541  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2542  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2543  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2544  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2545 
2546  ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2547  ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2548  ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2549  ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2550 
2551  ip0->hop_limit -= 1;
2552  ip1->hop_limit -= 1;
2553  ip2->hop_limit -= 1;
2554  ip3->hop_limit -= 1;
2555 
2556  new_l0 =
2557  clib_net_to_host_u16 (ip0->payload_length) +
2558  vec_len (sl0->rewrite_bsid);
2559  new_l1 =
2560  clib_net_to_host_u16 (ip1->payload_length) +
2561  vec_len (sl1->rewrite_bsid);
2562  new_l2 =
2563  clib_net_to_host_u16 (ip2->payload_length) +
2564  vec_len (sl2->rewrite_bsid);
2565  new_l3 =
2566  clib_net_to_host_u16 (ip3->payload_length) +
2567  vec_len (sl3->rewrite_bsid);
2568 
2569  ip0->payload_length = clib_host_to_net_u16 (new_l0);
2570  ip1->payload_length = clib_host_to_net_u16 (new_l1);
2571  ip2->payload_length = clib_host_to_net_u16 (new_l2);
2572  ip3->payload_length = clib_host_to_net_u16 (new_l3);
2573 
2574  sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2575  sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2576  sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2577  sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2578 
2579  ip0->dst_address.as_u64[0] =
2580  (sr0->segments + sr0->segments_left)->as_u64[0];
2581  ip0->dst_address.as_u64[1] =
2582  (sr0->segments + sr0->segments_left)->as_u64[1];
2583  ip1->dst_address.as_u64[0] =
2584  (sr1->segments + sr1->segments_left)->as_u64[0];
2585  ip1->dst_address.as_u64[1] =
2586  (sr1->segments + sr1->segments_left)->as_u64[1];
2587  ip2->dst_address.as_u64[0] =
2588  (sr2->segments + sr2->segments_left)->as_u64[0];
2589  ip2->dst_address.as_u64[1] =
2590  (sr2->segments + sr2->segments_left)->as_u64[1];
2591  ip3->dst_address.as_u64[0] =
2592  (sr3->segments + sr3->segments_left)->as_u64[0];
2593  ip3->dst_address.as_u64[1] =
2594  (sr3->segments + sr3->segments_left)->as_u64[1];
2595 
2596  ip6_ext_header_t *ip_ext;
2597  if (ip0 + 1 == (void *) sr0)
2598  {
2599  sr0->protocol = ip0->protocol;
2600  ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2601  }
2602  else
2603  {
2604  ip_ext = (void *) (ip0 + 1);
2605  sr0->protocol = ip_ext->next_hdr;
2606  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2607  }
2608 
2609  if (ip1 + 1 == (void *) sr1)
2610  {
2611  sr1->protocol = ip1->protocol;
2612  ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2613  }
2614  else
2615  {
2616  ip_ext = (void *) (ip2 + 1);
2617  sr2->protocol = ip_ext->next_hdr;
2618  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2619  }
2620 
2621  if (ip2 + 1 == (void *) sr2)
2622  {
2623  sr2->protocol = ip2->protocol;
2624  ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2625  }
2626  else
2627  {
2628  ip_ext = (void *) (ip2 + 1);
2629  sr2->protocol = ip_ext->next_hdr;
2630  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2631  }
2632 
2633  if (ip3 + 1 == (void *) sr3)
2634  {
2635  sr3->protocol = ip3->protocol;
2636  ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2637  }
2638  else
2639  {
2640  ip_ext = (void *) (ip3 + 1);
2641  sr3->protocol = ip_ext->next_hdr;
2642  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2643  }
2644 
2645  insert_pkts += 4;
2646 
2647  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2648  {
2650  {
2652  vlib_add_trace (vm, node, b0, sizeof (*tr));
2653  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2654  sizeof (tr->src.as_u8));
2655  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2656  sizeof (tr->dst.as_u8));
2657  }
2658 
2660  {
2662  vlib_add_trace (vm, node, b1, sizeof (*tr));
2663  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2664  sizeof (tr->src.as_u8));
2665  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2666  sizeof (tr->dst.as_u8));
2667  }
2668 
2670  {
2672  vlib_add_trace (vm, node, b2, sizeof (*tr));
2673  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2674  sizeof (tr->src.as_u8));
2675  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2676  sizeof (tr->dst.as_u8));
2677  }
2678 
2680  {
2682  vlib_add_trace (vm, node, b3, sizeof (*tr));
2683  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2684  sizeof (tr->src.as_u8));
2685  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2686  sizeof (tr->dst.as_u8));
2687  }
2688  }
2689 
2690  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2691  n_left_to_next, bi0, bi1, bi2, bi3,
2692  next0, next1, next2, next3);
2693  }
2694 
2695  /* Single loop for potentially the last three packets */
2696  while (n_left_from > 0 && n_left_to_next > 0)
2697  {
2698  u32 bi0;
2699  vlib_buffer_t *b0;
2700  ip6_header_t *ip0 = 0;
2701  ip6_sr_header_t *sr0 = 0;
2702  ip6_sr_sl_t *sl0;
2703  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2704  u16 new_l0 = 0;
2705 
2706  bi0 = from[0];
2707  to_next[0] = bi0;
2708  from += 1;
2709  to_next += 1;
2710  n_left_from -= 1;
2711  n_left_to_next -= 1;
2712 
2713  b0 = vlib_get_buffer (vm, bi0);
2714  sl0 =
2716  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2718  vec_len (sl0->rewrite_bsid));
2719 
2720  ip0 = vlib_buffer_get_current (b0);
2721 
2722  if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2723  sr0 =
2724  (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2725  ip6_ext_header_len (ip0 + 1));
2726  else
2727  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2728 
2729  clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2730  (void *) sr0 - (void *) ip0);
2731  clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2732  sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2733 
2734  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2735 
2736  ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2737  ip0->hop_limit -= 1;
2738  new_l0 =
2739  clib_net_to_host_u16 (ip0->payload_length) +
2740  vec_len (sl0->rewrite_bsid);
2741  ip0->payload_length = clib_host_to_net_u16 (new_l0);
2742 
2743  sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2744 
2745  ip0->dst_address.as_u64[0] =
2746  (sr0->segments + sr0->segments_left)->as_u64[0];
2747  ip0->dst_address.as_u64[1] =
2748  (sr0->segments + sr0->segments_left)->as_u64[1];
2749 
2750  if (ip0 + 1 == (void *) sr0)
2751  {
2752  sr0->protocol = ip0->protocol;
2753  ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2754  }
2755  else
2756  {
2757  ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2758  sr0->protocol = ip_ext->next_hdr;
2759  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2760  }
2761 
2762  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2764  {
2766  vlib_add_trace (vm, node, b0, sizeof (*tr));
2767  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2768  sizeof (tr->src.as_u8));
2769  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2770  sizeof (tr->dst.as_u8));
2771  }
2772 
2773  insert_pkts++;
2774 
2775  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2776  n_left_to_next, bi0, next0);
2777  }
2778 
2779  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2780  }
2781 
2782  /* Update counters */
2784  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2785  insert_pkts);
2787  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2788  bsid_pkts);
2789  return from_frame->n_vectors;
2790 }
2791 
2792 /* *INDENT-OFF* */
2794  .function = sr_policy_rewrite_b_insert,
2795  .name = "sr-pl-rewrite-b-insert",
2796  .vector_size = sizeof (u32),
2797  .format_trace = format_sr_policy_rewrite_trace,
2798  .type = VLIB_NODE_TYPE_INTERNAL,
2799  .n_errors = SR_POLICY_REWRITE_N_ERROR,
2800  .error_strings = sr_policy_rewrite_error_strings,
2801  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2802  .next_nodes = {
2803 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2805 #undef _
2806  },
2807 };
2808 /* *INDENT-ON* */
2809 
2810 /**
2811  * @brief Function BSID encapsulation
2812  */
2815  vlib_buffer_t * b0,
2816  ip6_header_t * ip0,
2817  ip6_sr_header_t * sr0, u32 * next0)
2818 {
2819  ip6_address_t *new_dst0;
2820 
2821  if (PREDICT_FALSE (!sr0))
2822  goto error_bsid_encaps;
2823 
2825  {
2826  if (PREDICT_TRUE (sr0->segments_left != 0))
2827  {
2828  sr0->segments_left -= 1;
2829  new_dst0 = (ip6_address_t *) (sr0->segments);
2830  new_dst0 += sr0->segments_left;
2831  ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2832  ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2833  return;
2834  }
2835  }
2836 
2837 error_bsid_encaps:
2838  *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2839  b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2840 }
2841 
2842 /**
2843  * @brief Graph node for applying a SR policy BSID - Encapsulation
2844  */
2845 static uword
2847  vlib_frame_t * from_frame)
2848 {
2849  ip6_sr_main_t *sm = &sr_main;
2850  u32 n_left_from, next_index, *from, *to_next;
2851 
2852  from = vlib_frame_vector_args (from_frame);
2853  n_left_from = from_frame->n_vectors;
2854 
2855  next_index = node->cached_next_index;
2856 
2857  int encap_pkts = 0, bsid_pkts = 0;
2858 
2859  while (n_left_from > 0)
2860  {
2861  u32 n_left_to_next;
2862 
2863  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2864 
2865  /* Quad - Loop */
2866  while (n_left_from >= 8 && n_left_to_next >= 4)
2867  {
2868  u32 bi0, bi1, bi2, bi3;
2869  vlib_buffer_t *b0, *b1, *b2, *b3;
2870  u32 next0, next1, next2, next3;
2871  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2872  ip6_header_t *ip0, *ip1, *ip2, *ip3;
2873  ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2874  ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2875  ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2876  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2877 
2878  /* Prefetch next iteration. */
2879  {
2880  vlib_buffer_t *p4, *p5, *p6, *p7;
2881 
2882  p4 = vlib_get_buffer (vm, from[4]);
2883  p5 = vlib_get_buffer (vm, from[5]);
2884  p6 = vlib_get_buffer (vm, from[6]);
2885  p7 = vlib_get_buffer (vm, from[7]);
2886 
2887  /* Prefetch the buffer header and packet for the N+2 loop iteration */
2888  vlib_prefetch_buffer_header (p4, LOAD);
2889  vlib_prefetch_buffer_header (p5, LOAD);
2890  vlib_prefetch_buffer_header (p6, LOAD);
2891  vlib_prefetch_buffer_header (p7, LOAD);
2892 
2897  }
2898 
2899  to_next[0] = bi0 = from[0];
2900  to_next[1] = bi1 = from[1];
2901  to_next[2] = bi2 = from[2];
2902  to_next[3] = bi3 = from[3];
2903  from += 4;
2904  to_next += 4;
2905  n_left_from -= 4;
2906  n_left_to_next -= 4;
2907 
2908  b0 = vlib_get_buffer (vm, bi0);
2909  b1 = vlib_get_buffer (vm, bi1);
2910  b2 = vlib_get_buffer (vm, bi2);
2911  b3 = vlib_get_buffer (vm, bi3);
2912 
2913  sl0 =
2915  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2916  sl1 =
2918  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2919  sl2 =
2921  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2922  sl3 =
2924  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2926  vec_len (sl0->rewrite));
2928  vec_len (sl1->rewrite));
2930  vec_len (sl2->rewrite));
2932  vec_len (sl3->rewrite));
2933 
2934  ip0_encap = vlib_buffer_get_current (b0);
2935  ip1_encap = vlib_buffer_get_current (b1);
2936  ip2_encap = vlib_buffer_get_current (b2);
2937  ip3_encap = vlib_buffer_get_current (b3);
2938 
2939  ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2940  IP_PROTOCOL_IPV6_ROUTE);
2941  ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2942  IP_PROTOCOL_IPV6_ROUTE);
2943  ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2944  IP_PROTOCOL_IPV6_ROUTE);
2945  ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2946  IP_PROTOCOL_IPV6_ROUTE);
2947 
2948  end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2949  end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2950  end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2951  end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2952 
2953  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
2954  sl0->rewrite, vec_len (sl0->rewrite));
2955  clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
2956  sl1->rewrite, vec_len (sl1->rewrite));
2957  clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
2958  sl2->rewrite, vec_len (sl2->rewrite));
2959  clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
2960  sl3->rewrite, vec_len (sl3->rewrite));
2961 
2962  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2963  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2964  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2965  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2966 
2967  ip0 = vlib_buffer_get_current (b0);
2968  ip1 = vlib_buffer_get_current (b1);
2969  ip2 = vlib_buffer_get_current (b2);
2970  ip3 = vlib_buffer_get_current (b3);
2971 
2972  encaps_processing_v6 (node, b0, ip0, ip0_encap);
2973  encaps_processing_v6 (node, b1, ip1, ip1_encap);
2974  encaps_processing_v6 (node, b2, ip2, ip2_encap);
2975  encaps_processing_v6 (node, b3, ip3, ip3_encap);
2976 
2977  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2978  {
2980  {
2982  vlib_add_trace (vm, node, b0, sizeof (*tr));
2983  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2984  sizeof (tr->src.as_u8));
2985  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2986  sizeof (tr->dst.as_u8));
2987  }
2988 
2990  {
2992  vlib_add_trace (vm, node, b1, sizeof (*tr));
2993  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2994  sizeof (tr->src.as_u8));
2995  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2996  sizeof (tr->dst.as_u8));
2997  }
2998 
3000  {
3002  vlib_add_trace (vm, node, b2, sizeof (*tr));
3003  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3004  sizeof (tr->src.as_u8));
3005  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3006  sizeof (tr->dst.as_u8));
3007  }
3008 
3010  {
3012  vlib_add_trace (vm, node, b3, sizeof (*tr));
3013  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3014  sizeof (tr->src.as_u8));
3015  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3016  sizeof (tr->dst.as_u8));
3017  }
3018  }
3019 
3020  encap_pkts += 4;
3021  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3022  n_left_to_next, bi0, bi1, bi2, bi3,
3023  next0, next1, next2, next3);
3024  }
3025 
3026  /* Single loop for potentially the last three packets */
3027  while (n_left_from > 0 && n_left_to_next > 0)
3028  {
3029  u32 bi0;
3030  vlib_buffer_t *b0;
3031  ip6_header_t *ip0 = 0, *ip0_encap = 0;
3032  ip6_ext_header_t *prev0;
3033  ip6_sr_header_t *sr0;
3034  ip6_sr_sl_t *sl0;
3035  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3036 
3037  bi0 = from[0];
3038  to_next[0] = bi0;
3039  from += 1;
3040  to_next += 1;
3041  n_left_from -= 1;
3042  n_left_to_next -= 1;
3043  b0 = vlib_get_buffer (vm, bi0);
3044 
3045  sl0 =
3047  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3049  vec_len (sl0->rewrite));
3050 
3051  ip0_encap = vlib_buffer_get_current (b0);
3052  ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3053  IP_PROTOCOL_IPV6_ROUTE);
3054  end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3055 
3056  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3057  sl0->rewrite, vec_len (sl0->rewrite));
3058  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3059 
3060  ip0 = vlib_buffer_get_current (b0);
3061 
3062  encaps_processing_v6 (node, b0, ip0, ip0_encap);
3063 
3064  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3066  {
3068  vlib_add_trace (vm, node, b0, sizeof (*tr));
3069  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3070  sizeof (tr->src.as_u8));
3071  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3072  sizeof (tr->dst.as_u8));
3073  }
3074 
3075  encap_pkts++;
3076  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3077  n_left_to_next, bi0, next0);
3078  }
3079 
3080  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3081  }
3082 
3083  /* Update counters */
3085  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3086  encap_pkts);
3088  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3089  bsid_pkts);
3090 
3091  return from_frame->n_vectors;
3092 }
3093 
3094 /* *INDENT-OFF* */
3096  .function = sr_policy_rewrite_b_encaps,
3097  .name = "sr-pl-rewrite-b-encaps",
3098  .vector_size = sizeof (u32),
3099  .format_trace = format_sr_policy_rewrite_trace,
3100  .type = VLIB_NODE_TYPE_INTERNAL,
3101  .n_errors = SR_POLICY_REWRITE_N_ERROR,
3102  .error_strings = sr_policy_rewrite_error_strings,
3103  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3104  .next_nodes = {
3105 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3107 #undef _
3108  },
3109 };
3110 /* *INDENT-ON* */
3111 
3112 /*************************** SR Segment Lists DPOs ****************************/
3113 static u8 *
3114 format_sr_segment_list_dpo (u8 * s, va_list * args)
3115 {
3116  ip6_sr_main_t *sm = &sr_main;
3118  ip6_sr_sl_t *sl;
3119 
3120  index_t index = va_arg (*args, index_t);
3121  CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3122  s = format (s, "SR: Segment List index:[%d]", index);
3123  s = format (s, "\n\tSegments:");
3124 
3125  sl = pool_elt_at_index (sm->sid_lists, index);
3126 
3127  s = format (s, "< ");
3128  vec_foreach (addr, sl->segments)
3129  {
3130  s = format (s, "%U, ", format_ip6_address, addr);
3131  }
3132  s = format (s, "\b\b > - ");
3133  s = format (s, "Weight: %u", sl->weight);
3134 
3135  return s;
3136 }
3137 
3138 const static dpo_vft_t sr_policy_rewrite_vft = {
3139  .dv_lock = sr_dpo_lock,
3140  .dv_unlock = sr_dpo_unlock,
3141  .dv_format = format_sr_segment_list_dpo,
3142 };
3143 
3144 const static char *const sr_pr_encaps_ip6_nodes[] = {
3145  "sr-pl-rewrite-encaps",
3146  NULL,
3147 };
3148 
3149 const static char *const sr_pr_encaps_ip4_nodes[] = {
3150  "sr-pl-rewrite-encaps-v4",
3151  NULL,
3152 };
3153 
3154 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3157 };
3158 
3159 const static char *const sr_pr_insert_ip6_nodes[] = {
3160  "sr-pl-rewrite-insert",
3161  NULL,
3162 };
3163 
3164 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3166 };
3167 
3168 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3169  "sr-pl-rewrite-b-insert",
3170  NULL,
3171 };
3172 
3173 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3175 };
3176 
3177 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3178  "sr-pl-rewrite-b-encaps",
3179  NULL,
3180 };
3181 
3182 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3184 };
3185 
3186 /********************* SR Policy Rewrite initialization ***********************/
3187 /**
3188  * @brief SR Policy Rewrite initialization
3189  */
3190 clib_error_t *
3192 {
3193  ip6_sr_main_t *sm = &sr_main;
3194 
3195  /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3196  mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3197  sizeof (ip6_address_t));
3198 
3199  /* Init SR VPO DPOs type */
3201  dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3202 
3204  dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3205 
3207  dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3208 
3210  dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3211 
3212  /* Register the L2 encaps node used in HW redirect */
3214 
3215  sm->fib_table_ip6 = (u32) ~ 0;
3216  sm->fib_table_ip4 = (u32) ~ 0;
3217 
3218  return 0;
3219 }
3220 
3222 
3223 
3224 /*
3225 * fd.io coding-style-patch-verification: ON
3226 *
3227 * Local Variables:
3228 * eval: (c-set-style "gnu")
3229 * End:
3230 */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
static clib_error_t * sr_policy_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI for &#39;sr policies&#39; command family.
u32 fib_table_create_and_lock(fib_protocol_t proto, const char *const fmt,...)
Create a new table with no table ID.
Definition: fib_table.c:985
static u8 * compute_rewrite_insert(ip6_address_t *sl)
SR rewrite string computation for SRH insertion (inline)
u32 fib_table_id_find_fib_index(fib_protocol_t proto, u32 table_id)
Definition: lookup.c:360
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:169
ip6_sr_main_t sr_main
Definition: sr.c:31
dpo_lock_fn_t dv_lock
A reference counting lock function.
Definition: dpo.h:335
sr_policy_rewrite_next_t
u8 type
Type (default is 0)
Definition: sr.h:85
#define vec_foreach_index(var, v)
Iterate over vector indices.
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
#define SR_POLICY_TYPE_SPRAY
Definition: sr.h:75
fib_node_index_t path_index
The index of the FIB path.
Definition: load_balance.h:71
#define foreach_sr_policy_rewrite_error
#define CLIB_UNUSED(x)
Definition: clib.h:79
A virtual function table regisitered for a DPO type.
Definition: dpo.h:330
static uword sr_policy_rewrite_b_insert(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Graph node for applying a SR policy into a packet.
fib_node_index_t fib_table_lookup_exact_match(u32 fib_index, const fib_prefix_t *prefix)
Perfom an exact match in the non-forwarding table.
Definition: fib_table.c:95
a
Definition: bitmap.h:516
dpo_id_t path_dpo
ID of the Data-path object.
Definition: load_balance.h:66
u32 fib_table
FIB table.
Definition: sr.h:93
static uword sr_policy_rewrite_b_encaps(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Graph node for applying a SR policy BSID - Encapsulation.
u64 as_u64
Definition: bihash_doc.h:63
#define PREDICT_TRUE(x)
Definition: clib.h:98
void sr_dpo_unlock(dpo_id_t *dpo)
no-op unlock function.
Definition: sr.c:47
u8 as_u8[16]
Definition: ip6_packet.h:48
u64 as_u64[2]
Definition: ip6_packet.h:51
static const char *const sr_pr_encaps_ip4_nodes[]
static int dpo_id_is_valid(const dpo_id_t *dpoi)
Return true if the DPO object is valid, i.e.
Definition: dpo.h:185
vlib_node_registration_t sr_policy_rewrite_b_encaps_node
(constructor) VLIB_REGISTER_NODE (sr_policy_rewrite_b_encaps_node)
#define NULL
Definition: clib.h:55
static u32 ip4_compute_flow_hash(const ip4_header_t *ip, flow_hash_config_t flow_hash_config)
Definition: ip4.h:295
uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:353
#define ethernet_buffer_header_size(b)
Determine the size of the Ethernet headers of the current frame in the buffer.
Definition: ethernet.h:390
int sr_policy_mod(ip6_address_t *bsid, u32 index, u32 fib_table, u8 operation, ip6_address_t *segments, u32 sl_index, u32 weight)
Modify an existing SR policy.
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:459
dpo_id_t ip4_dpo
DPO for Encaps IPv6.
Definition: sr.h:70
u8 src_address[6]
Definition: packet.h:54
#define VLIB_BUFFER_PRE_DATA_SIZE
Definition: buffer.h:51
static uword sr_policy_rewrite_insert(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Graph node for applying a SR policy into a packet.
ip6_address_t * segments
SIDs (key)
Definition: sr.h:61
static u8 * compute_rewrite_bsid(ip6_address_t *sl)
SR rewrite string computation for SRH insertion with BSID (inline)
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
#define vlib_validate_buffer_enqueue_x4(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, bi2, bi3, next0, next1, next2, next3)
Finish enqueueing four buffers forward in the graph.
Definition: buffer_node.h:138
static clib_error_t * set_sr_src_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:561
static ip6_sr_sl_t * create_sl(ip6_sr_policy_t *sr_policy, ip6_address_t *sl, u32 weight, u8 is_encap)
Creates a Segment List and adds it to an SR policy.
static const char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM]
#define IPv6_DEFAULT_HEADER_LENGTH
Definition: sr.h:33
u32 l2_sr_policy_rewrite_index
Definition: sr.h:191
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
#define ROUTING_HEADER_TYPE_SR
Definition: sr_packet.h:116
static u8 * format_sr_segment_list_dpo(u8 *s, va_list *args)
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:418
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
ip6_address_t src_address
Definition: ip6_packet.h:341
ip6_sr_steering_policy_t * steer_policies
Definition: sr.h:209
static_always_inline void encaps_processing_v6(vlib_node_runtime_t *node, vlib_buffer_t *b0, ip6_header_t *ip0, ip6_header_t *ip0_encap)
IPv6 encapsulation processing as per RFC2473.
vlib_node_registration_t sr_policy_rewrite_encaps_v4_node
(constructor) VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_v4_node)
u8 * rewrite_bsid
Precomputed rewrite header for bindingSID.
Definition: sr.h:66
vlib_node_registration_t sr_policy_rewrite_encaps_l2_node
(constructor) VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_l2_node)
static uword sr_policy_rewrite_encaps_l2(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Graph node for applying a SR policy into a L2 frame.
flow_hash_config_t fib_table_get_flow_hash_config(u32 fib_index, fib_protocol_t proto)
Get the flow hash configured used by the table.
Definition: fib_table.c:908
index_t load_balance_create(u32 n_buckets, dpo_proto_t lb_proto, flow_hash_config_t fhc)
Definition: load_balance.c:192
dpo_id_t ip6_dpo
DPO for Encaps/Insert IPv6.
Definition: sr.h:69
u32 * sw_iface_sr_policies
Definition: sr.h:215
vlib_node_registration_t sr_policy_rewrite_encaps_node
(constructor) VLIB_REGISTER_NODE (sr_policy_rewrite_encaps_node)
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:67
#define static_always_inline
Definition: clib.h:85
enum dpo_type_t_ dpo_type_t
Common types of data-path objects New types can be dynamically added using dpo_register_new_type() ...
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:376
static const char *const sr_pr_insert_ip6_nodes[]
static u32 l2_flow_hash(vlib_buffer_t *b0)
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
void fib_table_entry_special_remove(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Remove a &#39;special&#39; entry from the FIB.
Definition: fib_table.c:388
#define always_inline
Definition: clib.h:84
u8 dst_address[6]
Definition: packet.h:53
SR Segment List (SID list)
Definition: sr.h:59
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:164
Aggregrate type for a prefix.
Definition: fib_types.h:160
#define clib_error_return(e, args...)
Definition: error.h:111
void load_balance_multipath_update(const dpo_id_t *dpo, const load_balance_path_t *raw_nhs, load_balance_flags_t flags)
Definition: load_balance.c:482
static uword sr_policy_rewrite_encaps(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Graph node for applying a SR policy into an IPv6 packet.
unsigned long u64
Definition: types.h:89
static const char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM]
static u64 mac_to_u64(u8 *m)
fib_protocol_t dpo_proto_to_fib(dpo_proto_t dpo_proto)
Definition: fib_types.c:236
dpo_type_t dpo_register_new_type(const dpo_vft_t *vft, const char *const *const *nodes)
Create and register a new DPO type.
Definition: dpo.c:261
int sr_policy_del(ip6_address_t *bsid, u32 index)
Delete a SR policy.
static void update_replicate(ip6_sr_policy_t *sr_policy)
Updates the Replicate DPO after an SR Policy change.
void fib_table_unlock(u32 fib_index, fib_protocol_t proto)
Take a reference counting lock on the table.
Definition: fib_table.c:1058
vlib_node_registration_t sr_policy_rewrite_b_insert_node
(constructor) VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node)
Definition: fib_entry.h:231
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:397
vlib_node_registration_t sr_policy_rewrite_insert_node
(constructor) VLIB_REGISTER_NODE (sr_policy_rewrite_insert_node)
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:71
static const char *const sr_pr_bsid_insert_ip6_nodes[]
static dpo_type_t sr_pr_bsid_insert_dpo_type
struct _unformat_input_t unformat_input_t
#define SR_SEGMENT_LIST_WEIGHT_DEFAULT
Definition: sr.h:54
static u8 * compute_rewrite_encaps(ip6_address_t *sl)
SR rewrite string computation for IPv6 encapsulation (inline)
load-balancing over a choice of [un]equal cost paths
Definition: dpo.h:104
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:188
static u32 ip6_compute_flow_hash(const ip6_header_t *ip, flow_hash_config_t flow_hash_config)
Definition: ip6.h:389
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:241
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:374
#define PREDICT_FALSE(x)
Definition: clib.h:97
void sr_dpo_lock(dpo_id_t *dpo)
no-op lock function.
Definition: sr.c:38
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:805
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:216
static uword mhash_set(mhash_t *h, void *key, uword new_value, uword *old_value)
Definition: mhash.h:117
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:350
u8 is_encap
Mode (0 is SRH insert, 1 Encaps)
Definition: sr.h:95
static uword sr_policy_rewrite_encaps_v4(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Graph node for applying a SR policy into an IPv4 packet.
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:113
u32 weight
SID list weight (wECMP / UCMP)
Definition: sr.h:63
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1112
sr_policy_rewrite_error_t
#define ip6_ext_header_len(p)
Definition: ip6_packet.h:461
unformat_function_t unformat_ip6_address
Definition: format.h:94
void replicate_multipath_update(const dpo_id_t *dpo, load_balance_path_t *next_hops)
fib_node_index_t fib_table_entry_special_dpo_update(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, const dpo_id_t *dpo)
Update a &#39;special&#39; entry to the FIB that links to the DPO passed A special entry is an entry that the...
Definition: fib_table.c:327
#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
#define hash_mix64(a0, b0, c0)
Definition: hash.h:507
svmdb_client_t * c
u16 n_vectors
Definition: node.h:344
format_function_t format_ip6_address
Definition: format.h:95
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
vlib_main_t * vm
Definition: buffer.c:276
static const char *const sr_pr_bsid_encaps_ip6_nodes[]
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
static_always_inline void end_bsid_encaps_srh_processing(vlib_node_runtime_t *node, vlib_buffer_t *b0, ip6_header_t *ip0, ip6_sr_header_t *sr0, u32 *next0)
Function BSID encapsulation.
static u8 * format_sr_policy_rewrite_trace(u8 *s, va_list *args)
Trace for the SR Policy Rewrite graph node.
u32 * segments_lists
SID lists indexes (vector)
Definition: sr.h:81
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:85
#define clib_memcpy(a, b, c)
Definition: string.h:69
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:28
dpo_id_t bsid_dpo
DPO for Encaps/Insert for BSID.
Definition: sr.h:68
void dpo_set(dpo_id_t *dpo, dpo_type_t type, dpo_proto_t proto, index_t index)
Set/create a DPO ID The DPO will be locked.
Definition: dpo.c:157
index_t replicate_create(u32 n_buckets, dpo_proto_t rep_proto)
#define foreach_sr_policy_rewrite_next
clib_error_t * sr_policy_rewrite_init(vlib_main_t *vm)
SR Policy Rewrite initialization.
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
static const char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM]
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:455
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:255
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
static uword * mhash_get(mhash_t *h, const void *key)
Definition: mhash.h:110
static const char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM]
SR policy rewrite trace.
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:201
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
#define IP_FLOW_HASH_DEFAULT
Default: 5-tuple without the "reverse" bit.
Definition: lookup.h:152
static dpo_type_t sr_pr_encaps_dpo_type
Dynamically added SR SL DPO type.
static_always_inline void encaps_processing_v4(vlib_node_runtime_t *node, vlib_buffer_t *b0, ip6_header_t *ip0, ip4_header_t *ip0_encap)
IPv4 encapsulation processing as per RFC2473.
u32 flow_hash_config_t
A flow hash configuration is a mask of the flow hash options.
Definition: lookup.h:165
u64 uword
Definition: types.h:112
mhash_t sr_policies_index_hash
Definition: sr.h:200
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
int sr_policy_add(ip6_address_t *bsid, ip6_address_t *segments, u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
Create a new SR policy.
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:328
Definition: defs.h:47
unsigned short u16
Definition: types.h:57
#define DPO_PROTO_NUM
Definition: dpo.h:73
SRv6.
Definition: fib_entry.h:70
u16 payload_length
Definition: ip6_packet.h:332
i64 word
Definition: types.h:111
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:29
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
ip6_sr_policy_t * sr_policies
Definition: sr.h:197
unsigned char u8
Definition: types.h:56
u32 path_weight
weight for the path.
Definition: load_balance.h:76
ip6_address_t segments[0]
Definition: sr_packet.h:148
SR Policy.
Definition: sr.h:79
u8 * rewrite
Precomputed rewrite header.
Definition: sr.h:65
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:253
#define SR_POLICY_TYPE_DEFAULT
Definition: sr.h:74
dpo_id_t bsid_dpo
SR Policy specific DPO - BSID.
Definition: sr.h:89
static dpo_type_t sr_pr_insert_dpo_type
One path from an [EU]CMP set that the client wants to add to a load-balance object.
Definition: load_balance.h:62
ip6_sr_sl_t * sid_lists
Definition: sr.h:194
static char * sr_policy_rewrite_error_strings[]
#define vnet_buffer(b)
Definition: buffer.h:294
Segment Routing data structures definitions.
Segment Routing main datastructure.
Definition: sr.h:188
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
dpo_id_t ip6_dpo
SR Policy specific DPO - IPv4.
Definition: sr.h:91
u8 data[0]
Packet data.
Definition: buffer.h:152
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:194
#define vec_foreach(var, vec)
Vector iterator.
static const char *const sr_pr_encaps_ip6_nodes[]
#define ip6_ext_header_find_t(i, p, m, t)
Definition: ip6_packet.h:474
u32 fib_table_ip4
Definition: sr.h:232
u16 flags
Copy of main node flags.
Definition: node.h:449
vhost_vring_addr_t addr
Definition: vhost-user.h:84
u8 ip_version_and_header_length
Definition: ip4_packet.h:131
static dpo_type_t sr_pr_bsid_encaps_dpo_type
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:74
#define IPv6_DEFAULT_HOP_LIMIT
Definition: sr.h:34
dpo_id_t ip4_dpo
SR Policy specific DPO - IPv6.
Definition: sr.h:90
static ip6_address_t sr_pr_encaps_src
IPv6 SA for encapsulated packets.
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:577
u32 fib_table_ip6
Definition: sr.h:231
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
static void update_lb(ip6_sr_policy_t *sr_policy)
Updates the Load Balancer after an SR Policy change.
ip6_address_t bsid
BindingSID (key)
Definition: sr.h:83
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:971
static u32 ip_flow_hash(void *data)
Definition: defs.h:46
ip6_address_t dst_address
Definition: ip6_packet.h:341
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
static clib_error_t * show_sr_policies_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI to display onscreen all the SR policies.
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109