FD.io VPP  v17.07.01-10-g3be13f0
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/srv6/sr.h>
44 #include <vnet/ip/ip.h>
45 #include <vnet/srv6/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 */
380  sr_policy->fib_table),
381  &pfx, FIB_SOURCE_SR,
383  &sr_policy->bsid_dpo);
384 
386  &pfx,
389  &sr_policy->ip6_dpo);
390 
391  if (sr_policy->is_encap)
392  {
395 
397  &pfx,
400  &sr_policy->ip4_dpo);
401  }
402 
403  }
404 
405  /* Create the LB path vector */
406  //path_vector = vec_new(load_balance_path_t, vec_len(sr_policy->segments_lists));
407  vec_foreach (sl_index, sr_policy->segments_lists)
408  {
409  segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
410  path.path_dpo = segment_list->bsid_dpo;
411  path.path_weight = segment_list->weight;
412  vec_add1 (b_path_vector, path);
413  path.path_dpo = segment_list->ip6_dpo;
414  vec_add1 (ip6_path_vector, path);
415  if (sr_policy->is_encap)
416  {
417  path.path_dpo = segment_list->ip4_dpo;
418  vec_add1 (ip4_path_vector, path);
419  }
420  }
421 
422  /* Update LB multipath */
423  load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
425  load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
427  if (sr_policy->is_encap)
428  load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
430 
431  /* Cleanup */
432  vec_free (b_path_vector);
433  vec_free (ip6_path_vector);
434  vec_free (ip4_path_vector);
435 
436 }
437 
438 /**
439  * @brief Updates the Replicate DPO after an SR Policy change
440  *
441  * @param sr_policy is the modified SR Policy (type spray)
442  */
443 static inline void
445 {
446  u32 *sl_index;
447  ip6_sr_sl_t *segment_list;
448  ip6_sr_main_t *sm = &sr_main;
449  load_balance_path_t path;
451  load_balance_path_t *b_path_vector = 0;
452  load_balance_path_t *ip6_path_vector = 0;
453  load_balance_path_t *ip4_path_vector = 0;
454 
455  /* In case LB does not exist, create it */
456  if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
457  {
458  dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
460 
461  dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
463 
464  /* Update FIB entry's DPO to point to SR without LB */
465  fib_prefix_t pfx = {
467  .fp_len = 128,
468  .fp_addr = {
469  .ip6 = sr_policy->bsid,
470  }
471  };
473  sr_policy->fib_table),
474  &pfx, FIB_SOURCE_SR,
476  &sr_policy->bsid_dpo);
477 
479  &pfx,
482  &sr_policy->ip6_dpo);
483 
484  if (sr_policy->is_encap)
485  {
488 
490  &pfx,
493  &sr_policy->ip4_dpo);
494  }
495 
496  }
497 
498  /* Create the replicate path vector */
499  path.path_weight = 1;
500  vec_foreach (sl_index, sr_policy->segments_lists)
501  {
502  segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
503  path.path_dpo = segment_list->bsid_dpo;
504  vec_add1 (b_path_vector, path);
505  path.path_dpo = segment_list->ip6_dpo;
506  vec_add1 (ip6_path_vector, path);
507  if (sr_policy->is_encap)
508  {
509  path.path_dpo = segment_list->ip4_dpo;
510  vec_add1 (ip4_path_vector, path);
511  }
512  }
513 
514  /* Update replicate multipath */
515  replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
516  replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
517  if (sr_policy->is_encap)
518  replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
519 }
520 
521 /******************************* SR rewrite API *******************************/
522 /* Three functions for handling sr policies:
523  * -> sr_policy_add
524  * -> sr_policy_del
525  * -> sr_policy_mod
526  * All of them are API. CLI function on sr_policy_command_fn */
527 
528 /**
529  * @brief Create a new SR policy
530  *
531  * @param bsid is the bindingSID of the SR Policy
532  * @param segments is a vector of IPv6 address composing the segment list
533  * @param weight is the weight of the sid list. optional.
534  * @param behavior is the behavior of the SR policy. (default//spray)
535  * @param fib_table is the VRF where to install the FIB entry for the BSID
536  * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
537  *
538  * @return 0 if correct, else error
539  */
540 int
542  u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
543 {
544  ip6_sr_main_t *sm = &sr_main;
545  ip6_sr_policy_t *sr_policy = 0;
546  uword *p;
547 
548  /* Search for existing keys (BSID) */
549  p = mhash_get (&sm->sr_policies_index_hash, bsid);
550  if (p)
551  {
552  /* Add SR policy that already exists; complain */
553  return -12;
554  }
555 
556  /* Search collision in FIB entries */
557  /* Explanation: It might be possible that some other entity has already
558  * created a route for the BSID. This in theory is impossible, but in
559  * practise we could see it. Assert it and scream if needed */
560  fib_prefix_t pfx = {
562  .fp_len = 128,
563  .fp_addr = {
564  .ip6 = *bsid,
565  }
566  };
567 
568  /* Lookup the FIB index associated to the table selected */
569  u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
570  (fib_table != (u32) ~ 0 ? fib_table : 0));
571  if (fib_index == ~0)
572  return -13;
573 
574  /* Lookup whether there exists an entry for the BSID */
575  fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
576  if (FIB_NODE_INDEX_INVALID != fei)
577  return -12; //There is an entry for such lookup
578 
579  /* Add an SR policy object */
580  pool_get (sm->sr_policies, sr_policy);
581  memset (sr_policy, 0, sizeof (*sr_policy));
582  clib_memcpy (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
583  sr_policy->type = behavior;
584  sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
585  sr_policy->is_encap = is_encap;
586 
587  /* Copy the key */
588  mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
589  NULL);
590 
591  /* Create a segment list and add the index to the SR policy */
592  create_sl (sr_policy, segments, weight, is_encap);
593 
594  /* If FIB doesnt exist, create them */
595  if (sm->fib_table_ip6 == (u32) ~ 0)
596  {
598  "SRv6 steering of IP6 prefixes through BSIDs");
600  "SRv6 steering of IP4 prefixes through BSIDs");
601  }
602 
603  /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
604  if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
605  update_lb (sr_policy);
606  else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
607  update_replicate (sr_policy);
608  return 0;
609 }
610 
611 /**
612  * @brief Delete a SR policy
613  *
614  * @param bsid is the bindingSID of the SR Policy
615  * @param index is the index of the SR policy
616  *
617  * @return 0 if correct, else error
618  */
619 int
621 {
622  ip6_sr_main_t *sm = &sr_main;
623  ip6_sr_policy_t *sr_policy = 0;
624  ip6_sr_sl_t *segment_list;
625  u32 *sl_index;
626  uword *p;
627 
628  if (bsid)
629  {
630  p = mhash_get (&sm->sr_policies_index_hash, bsid);
631  if (p)
632  sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
633  else
634  return -1;
635  }
636  else
637  {
638  sr_policy = pool_elt_at_index (sm->sr_policies, index);
639  if (!sr_policy)
640  return -1;
641  }
642 
643  /* Remove BindingSID FIB entry */
644  fib_prefix_t pfx = {
646  .fp_len = 128,
647  .fp_addr = {
648  .ip6 = sr_policy->bsid,
649  }
650  ,
651  };
652 
654  sr_policy->fib_table),
655  &pfx, FIB_SOURCE_SR);
656 
658 
659  if (sr_policy->is_encap)
661 
662  if (dpo_id_is_valid (&sr_policy->bsid_dpo))
663  {
664  dpo_reset (&sr_policy->bsid_dpo);
665  dpo_reset (&sr_policy->ip4_dpo);
666  dpo_reset (&sr_policy->ip6_dpo);
667  }
668 
669  /* Clean SID Lists */
670  vec_foreach (sl_index, sr_policy->segments_lists)
671  {
672  segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
673  vec_free (segment_list->segments);
674  vec_free (segment_list->rewrite);
675  vec_free (segment_list->rewrite_bsid);
676  pool_put_index (sm->sid_lists, *sl_index);
677  }
678 
679  /* Remove SR policy entry */
680  mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
681  pool_put (sm->sr_policies, sr_policy);
682 
683  /* If FIB empty unlock it */
684  if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
685  {
688  sm->fib_table_ip6 = (u32) ~ 0;
689  sm->fib_table_ip4 = (u32) ~ 0;
690  }
691 
692  return 0;
693 }
694 
695 /**
696  * @brief Modify an existing SR policy
697  *
698  * The possible modifications are adding a new Segment List, modifying an
699  * existing Segment List (modify the weight only) and delete a given
700  * Segment List from the SR Policy.
701  *
702  * @param bsid is the bindingSID of the SR Policy
703  * @param index is the index of the SR policy
704  * @param fib_table is the VRF where to install the FIB entry for the BSID
705  * @param operation is the operation to perform (among the top ones)
706  * @param segments is a vector of IPv6 address composing the segment list
707  * @param sl_index is the index of the Segment List to modify/delete
708  * @param weight is the weight of the sid list. optional.
709  * @param is_encap Mode. Encapsulation or SRH insertion.
710  *
711  * @return 0 if correct, else error
712  */
713 int
714 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
715  u8 operation, ip6_address_t * segments, u32 sl_index,
716  u32 weight)
717 {
718  ip6_sr_main_t *sm = &sr_main;
719  ip6_sr_policy_t *sr_policy = 0;
720  ip6_sr_sl_t *segment_list;
721  u32 *sl_index_iterate;
722  uword *p;
723 
724  if (bsid)
725  {
726  p = mhash_get (&sm->sr_policies_index_hash, bsid);
727  if (p)
728  sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
729  else
730  return -1;
731  }
732  else
733  {
734  sr_policy = pool_elt_at_index (sm->sr_policies, index);
735  if (!sr_policy)
736  return -1;
737  }
738 
739  if (operation == 1) /* Add SR List to an existing SR policy */
740  {
741  /* Create the new SL */
742  segment_list =
743  create_sl (sr_policy, segments, weight, sr_policy->is_encap);
744 
745  /* Create a new LB DPO */
746  if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
747  update_lb (sr_policy);
748  else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
749  update_replicate (sr_policy);
750  }
751  else if (operation == 2) /* Delete SR List from an existing SR policy */
752  {
753  /* Check that currently there are more than one SID list */
754  if (vec_len (sr_policy->segments_lists) == 1)
755  return -21;
756 
757  /* Check that the SR list does exist and is assigned to the sr policy */
758  vec_foreach (sl_index_iterate, sr_policy->segments_lists)
759  if (*sl_index_iterate == sl_index)
760  break;
761 
762  if (*sl_index_iterate != sl_index)
763  return -22;
764 
765  /* Remove the lucky SR list that is being kicked out */
766  segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
767  vec_free (segment_list->segments);
768  vec_free (segment_list->rewrite);
769  vec_free (segment_list->rewrite_bsid);
770  pool_put_index (sm->sid_lists, sl_index);
771  vec_del1 (sr_policy->segments_lists,
772  sl_index_iterate - sr_policy->segments_lists);
773 
774  /* Create a new LB DPO */
775  if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
776  update_lb (sr_policy);
777  else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
778  update_replicate (sr_policy);
779  }
780  else if (operation == 3) /* Modify the weight of an existing SR List */
781  {
782  /* Find the corresponding SL */
783  vec_foreach (sl_index_iterate, sr_policy->segments_lists)
784  if (*sl_index_iterate == sl_index)
785  break;
786 
787  if (*sl_index_iterate != sl_index)
788  return -32;
789 
790  /* Change the weight */
791  segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
792  segment_list->weight = weight;
793 
794  /* Update LB */
795  if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
796  update_lb (sr_policy);
797  }
798  else /* Incorrect op. */
799  return -1;
800 
801  return 0;
802 }
803 
804 /**
805  * @brief CLI for 'sr policies' command family
806  */
807 static clib_error_t *
809  vlib_cli_command_t * cmd)
810 {
811  int rv = -1;
812  char is_del = 0, is_add = 0, is_mod = 0;
813  char policy_set = 0;
814  ip6_address_t bsid, next_address;
815  u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
816  u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
817  ip6_address_t *segments = 0, *this_seg;
818  u8 operation = 0;
819  char is_encap = 1;
820  char is_spray = 0;
821 
823  {
824  if (!is_add && !is_mod && !is_del && unformat (input, "add"))
825  is_add = 1;
826  else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
827  is_del = 1;
828  else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
829  is_mod = 1;
830  else if (!policy_set
831  && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
832  policy_set = 1;
833  else if (!is_add && !policy_set
834  && unformat (input, "index %d", &sr_policy_index))
835  policy_set = 1;
836  else if (unformat (input, "weight %d", &weight));
837  else
838  if (unformat (input, "next %U", unformat_ip6_address, &next_address))
839  {
840  vec_add2 (segments, this_seg, 1);
841  clib_memcpy (this_seg->as_u8, next_address.as_u8,
842  sizeof (*this_seg));
843  }
844  else if (unformat (input, "add sl"))
845  operation = 1;
846  else if (unformat (input, "del sl index %d", &sl_index))
847  operation = 2;
848  else if (unformat (input, "mod sl index %d", &sl_index))
849  operation = 3;
850  else if (fib_table == (u32) ~ 0
851  && unformat (input, "fib-table %d", &fib_table));
852  else if (unformat (input, "encap"))
853  is_encap = 1;
854  else if (unformat (input, "insert"))
855  is_encap = 0;
856  else if (unformat (input, "spray"))
857  is_spray = 1;
858  else
859  break;
860  }
861 
862  if (!is_add && !is_mod && !is_del)
863  return clib_error_return (0, "Incorrect CLI");
864 
865  if (!policy_set)
866  return clib_error_return (0, "No SR policy BSID or index specified");
867 
868  if (is_add)
869  {
870  if (vec_len (segments) == 0)
871  return clib_error_return (0, "No Segment List specified");
872  rv = sr_policy_add (&bsid, segments, weight,
873  (is_spray ? SR_POLICY_TYPE_SPRAY :
874  SR_POLICY_TYPE_DEFAULT), fib_table, is_encap);
875  }
876  else if (is_del)
877  rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
878  sr_policy_index);
879  else if (is_mod)
880  {
881  if (!operation)
882  return clib_error_return (0, "No SL modification specified");
883  if (operation != 1 && sl_index == (u32) ~ 0)
884  return clib_error_return (0, "No Segment List index specified");
885  if (operation == 1 && vec_len (segments) == 0)
886  return clib_error_return (0, "No Segment List specified");
887  if (operation == 3 && weight == (u32) ~ 0)
888  return clib_error_return (0, "No new weight for the SL specified");
889  rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
890  sr_policy_index, fib_table, operation, segments,
891  sl_index, weight);
892  }
893 
894  switch (rv)
895  {
896  case 0:
897  break;
898  case 1:
899  return 0;
900  case -12:
901  return clib_error_return (0,
902  "There is already a FIB entry for the BindingSID address.\n"
903  "The SR policy could not be created.");
904  case -13:
905  return clib_error_return (0, "The specified FIB table does not exist.");
906  case -21:
907  return clib_error_return (0,
908  "The selected SR policy only contains ONE segment list. "
909  "Please remove the SR policy instead");
910  case -22:
911  return clib_error_return (0,
912  "Could not delete the segment list. "
913  "It is not associated with that SR policy.");
914  case -32:
915  return clib_error_return (0,
916  "Could not modify the segment list. "
917  "The given SL is not associated with such SR policy.");
918  default:
919  return clib_error_return (0, "BUG: sr policy returns %d", rv);
920  }
921  return 0;
922 }
923 
924 /* *INDENT-OFF* */
925 VLIB_CLI_COMMAND (sr_policy_command, static) = {
926  .path = "sr policy",
927  .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
928  "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
929  .long_help =
930  "Manipulation of SR policies.\n"
931  "A Segment Routing policy may contain several SID lists. Each SID list has\n"
932  "an associated weight (default 1), which will result in wECMP (uECMP).\n"
933  "Segment Routing policies might be of type encapsulation or srh insertion\n"
934  "Each SR policy will be associated with a unique BindingSID.\n"
935  "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
936  "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
937  "The add command will create a SR policy with its first segment list (sl)\n"
938  "The mod command allows you to add, remove, or modify the existing segment lists\n"
939  "within an SR policy.\n"
940  "The del command allows you to delete a SR policy along with all its associated\n"
941  "SID lists.\n",
942  .function = sr_policy_command_fn,
943 };
944 /* *INDENT-ON* */
945 
946 /**
947  * @brief CLI to display onscreen all the SR policies
948  */
949 static clib_error_t *
951  vlib_cli_command_t * cmd)
952 {
953  ip6_sr_main_t *sm = &sr_main;
954  u32 *sl_index;
955  ip6_sr_sl_t *segment_list = 0;
956  ip6_sr_policy_t *sr_policy = 0;
957  ip6_sr_policy_t **vec_policies = 0;
959  u8 *s;
960  int i = 0;
961 
962  vlib_cli_output (vm, "SR policies:");
963 
964  /* *INDENT-OFF* */
965  pool_foreach (sr_policy, sm->sr_policies,
966  {vec_add1 (vec_policies, sr_policy); } );
967  /* *INDENT-ON* */
968 
969  vec_foreach_index (i, vec_policies)
970  {
971  sr_policy = vec_policies[i];
972  vlib_cli_output (vm, "[%u].-\tBSID: %U",
973  (u32) (sr_policy - sm->sr_policies),
974  format_ip6_address, &sr_policy->bsid);
975  vlib_cli_output (vm, "\tBehavior: %s",
976  (sr_policy->is_encap ? "Encapsulation" :
977  "SRH insertion"));
978  vlib_cli_output (vm, "\tType: %s",
979  (sr_policy->type ==
980  SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
981  vlib_cli_output (vm, "\tFIB table: %u",
982  (sr_policy->fib_table !=
983  (u32) ~ 0 ? sr_policy->fib_table : 0));
984  vlib_cli_output (vm, "\tSegment Lists:");
985  vec_foreach (sl_index, sr_policy->segments_lists)
986  {
987  s = NULL;
988  s = format (s, "\t[%u].- ", *sl_index);
989  segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
990  s = format (s, "< ");
991  vec_foreach (addr, segment_list->segments)
992  {
993  s = format (s, "%U, ", format_ip6_address, addr);
994  }
995  s = format (s, "\b\b > ");
996  s = format (s, "weight: %u", segment_list->weight);
997  vlib_cli_output (vm, " %s", s);
998  }
999  vlib_cli_output (vm, "-----------");
1000  }
1001  return 0;
1002 }
1003 
1004 /* *INDENT-OFF* */
1005 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1006  .path = "show sr policies",
1007  .short_help = "show sr policies",
1008  .function = show_sr_policies_command_fn,
1009 };
1010 /* *INDENT-ON* */
1011 
1012 /*************************** SR rewrite graph node ****************************/
1013 /**
1014  * @brief Trace for the SR Policy Rewrite graph node
1015  */
1016 static u8 *
1017 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1018 {
1019  //TODO
1020  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1021  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1023 
1024  s = format
1025  (s, "SR-policy-rewrite: src %U dst %U",
1027 
1028  return s;
1029 }
1030 
1031 /**
1032  * @brief IPv6 encapsulation processing as per RFC2473
1033  */
1036  vlib_buffer_t * b0,
1037  ip6_header_t * ip0, ip6_header_t * ip0_encap)
1038 {
1039  u32 new_l0;
1040 
1041  ip0_encap->hop_limit -= 1;
1042  new_l0 =
1043  ip0->payload_length + sizeof (ip6_header_t) +
1044  clib_net_to_host_u16 (ip0_encap->payload_length);
1045  ip0->payload_length = clib_host_to_net_u16 (new_l0);
1048 }
1049 
1050 /**
1051  * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1052  */
1053 static uword
1055  vlib_frame_t * from_frame)
1056 {
1057  ip6_sr_main_t *sm = &sr_main;
1058  u32 n_left_from, next_index, *from, *to_next;
1059 
1060  from = vlib_frame_vector_args (from_frame);
1061  n_left_from = from_frame->n_vectors;
1062 
1063  next_index = node->cached_next_index;
1064 
1065  int encap_pkts = 0, bsid_pkts = 0;
1066 
1067  while (n_left_from > 0)
1068  {
1069  u32 n_left_to_next;
1070 
1071  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1072 
1073  /* Quad - Loop */
1074  while (n_left_from >= 8 && n_left_to_next >= 4)
1075  {
1076  u32 bi0, bi1, bi2, bi3;
1077  vlib_buffer_t *b0, *b1, *b2, *b3;
1078  u32 next0, next1, next2, next3;
1079  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1080  ip6_header_t *ip0, *ip1, *ip2, *ip3;
1081  ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1082  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1083 
1084  /* Prefetch next iteration. */
1085  {
1086  vlib_buffer_t *p4, *p5, *p6, *p7;
1087 
1088  p4 = vlib_get_buffer (vm, from[4]);
1089  p5 = vlib_get_buffer (vm, from[5]);
1090  p6 = vlib_get_buffer (vm, from[6]);
1091  p7 = vlib_get_buffer (vm, from[7]);
1092 
1093  /* Prefetch the buffer header and packet for the N+2 loop iteration */
1094  vlib_prefetch_buffer_header (p4, LOAD);
1095  vlib_prefetch_buffer_header (p5, LOAD);
1096  vlib_prefetch_buffer_header (p6, LOAD);
1097  vlib_prefetch_buffer_header (p7, LOAD);
1098 
1103  }
1104 
1105  to_next[0] = bi0 = from[0];
1106  to_next[1] = bi1 = from[1];
1107  to_next[2] = bi2 = from[2];
1108  to_next[3] = bi3 = from[3];
1109  from += 4;
1110  to_next += 4;
1111  n_left_from -= 4;
1112  n_left_to_next -= 4;
1113 
1114  b0 = vlib_get_buffer (vm, bi0);
1115  b1 = vlib_get_buffer (vm, bi1);
1116  b2 = vlib_get_buffer (vm, bi2);
1117  b3 = vlib_get_buffer (vm, bi3);
1118 
1119  sl0 =
1121  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1122  sl1 =
1124  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1125  sl2 =
1127  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1128  sl3 =
1130  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1131 
1133  vec_len (sl0->rewrite));
1135  vec_len (sl1->rewrite));
1137  vec_len (sl2->rewrite));
1139  vec_len (sl3->rewrite));
1140 
1141  ip0_encap = vlib_buffer_get_current (b0);
1142  ip1_encap = vlib_buffer_get_current (b1);
1143  ip2_encap = vlib_buffer_get_current (b2);
1144  ip3_encap = vlib_buffer_get_current (b3);
1145 
1146  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1147  sl0->rewrite, vec_len (sl0->rewrite));
1148  clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1149  sl1->rewrite, vec_len (sl1->rewrite));
1150  clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1151  sl2->rewrite, vec_len (sl2->rewrite));
1152  clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1153  sl3->rewrite, vec_len (sl3->rewrite));
1154 
1155  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1156  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1157  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1158  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1159 
1160  ip0 = vlib_buffer_get_current (b0);
1161  ip1 = vlib_buffer_get_current (b1);
1162  ip2 = vlib_buffer_get_current (b2);
1163  ip3 = vlib_buffer_get_current (b3);
1164 
1165  encaps_processing_v6 (node, b0, ip0, ip0_encap);
1166  encaps_processing_v6 (node, b1, ip1, ip1_encap);
1167  encaps_processing_v6 (node, b2, ip2, ip2_encap);
1168  encaps_processing_v6 (node, b3, ip3, ip3_encap);
1169 
1170  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1171  {
1173  {
1175  vlib_add_trace (vm, node, b0, sizeof (*tr));
1176  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1177  sizeof (tr->src.as_u8));
1178  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1179  sizeof (tr->dst.as_u8));
1180  }
1181 
1183  {
1185  vlib_add_trace (vm, node, b1, sizeof (*tr));
1186  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1187  sizeof (tr->src.as_u8));
1188  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1189  sizeof (tr->dst.as_u8));
1190  }
1191 
1193  {
1195  vlib_add_trace (vm, node, b2, sizeof (*tr));
1196  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1197  sizeof (tr->src.as_u8));
1198  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1199  sizeof (tr->dst.as_u8));
1200  }
1201 
1203  {
1205  vlib_add_trace (vm, node, b3, sizeof (*tr));
1206  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1207  sizeof (tr->src.as_u8));
1208  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1209  sizeof (tr->dst.as_u8));
1210  }
1211  }
1212 
1213  encap_pkts += 4;
1214  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1215  n_left_to_next, bi0, bi1, bi2, bi3,
1216  next0, next1, next2, next3);
1217  }
1218 
1219  /* Single loop for potentially the last three packets */
1220  while (n_left_from > 0 && n_left_to_next > 0)
1221  {
1222  u32 bi0;
1223  vlib_buffer_t *b0;
1224  ip6_header_t *ip0 = 0, *ip0_encap = 0;
1225  ip6_sr_sl_t *sl0;
1226  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1227 
1228  bi0 = from[0];
1229  to_next[0] = bi0;
1230  from += 1;
1231  to_next += 1;
1232  n_left_from -= 1;
1233  n_left_to_next -= 1;
1234  b0 = vlib_get_buffer (vm, bi0);
1235 
1236  sl0 =
1238  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1240  vec_len (sl0->rewrite));
1241 
1242  ip0_encap = vlib_buffer_get_current (b0);
1243 
1244  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1245  sl0->rewrite, vec_len (sl0->rewrite));
1246  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1247 
1248  ip0 = vlib_buffer_get_current (b0);
1249 
1250  encaps_processing_v6 (node, b0, ip0, ip0_encap);
1251 
1252  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1254  {
1256  vlib_add_trace (vm, node, b0, sizeof (*tr));
1257  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1258  sizeof (tr->src.as_u8));
1259  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1260  sizeof (tr->dst.as_u8));
1261  }
1262 
1263  encap_pkts++;
1264  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1265  n_left_to_next, bi0, next0);
1266  }
1267 
1268  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1269  }
1270 
1271  /* Update counters */
1273  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1274  encap_pkts);
1276  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1277  bsid_pkts);
1278 
1279  return from_frame->n_vectors;
1280 }
1281 
1282 /* *INDENT-OFF* */
1284  .function = sr_policy_rewrite_encaps,
1285  .name = "sr-pl-rewrite-encaps",
1286  .vector_size = sizeof (u32),
1287  .format_trace = format_sr_policy_rewrite_trace,
1288  .type = VLIB_NODE_TYPE_INTERNAL,
1289  .n_errors = SR_POLICY_REWRITE_N_ERROR,
1290  .error_strings = sr_policy_rewrite_error_strings,
1291  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1292  .next_nodes = {
1293 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1295 #undef _
1296  },
1297 };
1298 /* *INDENT-ON* */
1299 
1300 /**
1301  * @brief IPv4 encapsulation processing as per RFC2473
1302  */
1305  vlib_buffer_t * b0,
1306  ip6_header_t * ip0, ip4_header_t * ip0_encap)
1307 {
1308  u32 new_l0;
1309  ip6_sr_header_t *sr0;
1310 
1311  u32 checksum0;
1312 
1313  /* Inner IPv4: Decrement TTL & update checksum */
1314  ip0_encap->ttl -= 1;
1315  checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1316  checksum0 += checksum0 >= 0xffff;
1317  ip0_encap->checksum = checksum0;
1318 
1319  /* Outer IPv6: Update length, FL, proto */
1320  new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1321  ip0->payload_length = clib_host_to_net_u16 (new_l0);
1323  clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1324  ((ip0_encap->tos & 0xFF) << 20));
1325  sr0 = (void *) (ip0 + 1);
1326  sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1327 }
1328 
1329 /**
1330  * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1331  */
1332 static uword
1334  vlib_frame_t * from_frame)
1335 {
1336  ip6_sr_main_t *sm = &sr_main;
1337  u32 n_left_from, next_index, *from, *to_next;
1338 
1339  from = vlib_frame_vector_args (from_frame);
1340  n_left_from = from_frame->n_vectors;
1341 
1342  next_index = node->cached_next_index;
1343 
1344  int encap_pkts = 0, bsid_pkts = 0;
1345 
1346  while (n_left_from > 0)
1347  {
1348  u32 n_left_to_next;
1349 
1350  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1351 
1352  /* Quad - Loop */
1353  while (n_left_from >= 8 && n_left_to_next >= 4)
1354  {
1355  u32 bi0, bi1, bi2, bi3;
1356  vlib_buffer_t *b0, *b1, *b2, *b3;
1357  u32 next0, next1, next2, next3;
1358  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1359  ip6_header_t *ip0, *ip1, *ip2, *ip3;
1360  ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1361  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1362 
1363  /* Prefetch next iteration. */
1364  {
1365  vlib_buffer_t *p4, *p5, *p6, *p7;
1366 
1367  p4 = vlib_get_buffer (vm, from[4]);
1368  p5 = vlib_get_buffer (vm, from[5]);
1369  p6 = vlib_get_buffer (vm, from[6]);
1370  p7 = vlib_get_buffer (vm, from[7]);
1371 
1372  /* Prefetch the buffer header and packet for the N+2 loop iteration */
1373  vlib_prefetch_buffer_header (p4, LOAD);
1374  vlib_prefetch_buffer_header (p5, LOAD);
1375  vlib_prefetch_buffer_header (p6, LOAD);
1376  vlib_prefetch_buffer_header (p7, LOAD);
1377 
1382  }
1383 
1384  to_next[0] = bi0 = from[0];
1385  to_next[1] = bi1 = from[1];
1386  to_next[2] = bi2 = from[2];
1387  to_next[3] = bi3 = from[3];
1388  from += 4;
1389  to_next += 4;
1390  n_left_from -= 4;
1391  n_left_to_next -= 4;
1392 
1393  b0 = vlib_get_buffer (vm, bi0);
1394  b1 = vlib_get_buffer (vm, bi1);
1395  b2 = vlib_get_buffer (vm, bi2);
1396  b3 = vlib_get_buffer (vm, bi3);
1397 
1398  sl0 =
1400  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1401  sl1 =
1403  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1404  sl2 =
1406  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1407  sl3 =
1409  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1411  vec_len (sl0->rewrite));
1413  vec_len (sl1->rewrite));
1415  vec_len (sl2->rewrite));
1417  vec_len (sl3->rewrite));
1418 
1419  ip0_encap = vlib_buffer_get_current (b0);
1420  ip1_encap = vlib_buffer_get_current (b1);
1421  ip2_encap = vlib_buffer_get_current (b2);
1422  ip3_encap = vlib_buffer_get_current (b3);
1423 
1424  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1425  sl0->rewrite, vec_len (sl0->rewrite));
1426  clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1427  sl1->rewrite, vec_len (sl1->rewrite));
1428  clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1429  sl2->rewrite, vec_len (sl2->rewrite));
1430  clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1431  sl3->rewrite, vec_len (sl3->rewrite));
1432 
1433  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1434  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1435  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1436  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1437 
1438  ip0 = vlib_buffer_get_current (b0);
1439  ip1 = vlib_buffer_get_current (b1);
1440  ip2 = vlib_buffer_get_current (b2);
1441  ip3 = vlib_buffer_get_current (b3);
1442 
1443  encaps_processing_v4 (node, b0, ip0, ip0_encap);
1444  encaps_processing_v4 (node, b1, ip1, ip1_encap);
1445  encaps_processing_v4 (node, b2, ip2, ip2_encap);
1446  encaps_processing_v4 (node, b3, ip3, ip3_encap);
1447 
1448  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1449  {
1451  {
1453  vlib_add_trace (vm, node, b0, sizeof (*tr));
1454  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1455  sizeof (tr->src.as_u8));
1456  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1457  sizeof (tr->dst.as_u8));
1458  }
1459 
1461  {
1463  vlib_add_trace (vm, node, b1, sizeof (*tr));
1464  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1465  sizeof (tr->src.as_u8));
1466  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1467  sizeof (tr->dst.as_u8));
1468  }
1469 
1471  {
1473  vlib_add_trace (vm, node, b2, sizeof (*tr));
1474  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1475  sizeof (tr->src.as_u8));
1476  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1477  sizeof (tr->dst.as_u8));
1478  }
1479 
1481  {
1483  vlib_add_trace (vm, node, b3, sizeof (*tr));
1484  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1485  sizeof (tr->src.as_u8));
1486  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1487  sizeof (tr->dst.as_u8));
1488  }
1489  }
1490 
1491  encap_pkts += 4;
1492  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1493  n_left_to_next, bi0, bi1, bi2, bi3,
1494  next0, next1, next2, next3);
1495  }
1496 
1497  /* Single loop for potentially the last three packets */
1498  while (n_left_from > 0 && n_left_to_next > 0)
1499  {
1500  u32 bi0;
1501  vlib_buffer_t *b0;
1502  ip6_header_t *ip0 = 0;
1503  ip4_header_t *ip0_encap = 0;
1504  ip6_sr_sl_t *sl0;
1505  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1506 
1507  bi0 = from[0];
1508  to_next[0] = bi0;
1509  from += 1;
1510  to_next += 1;
1511  n_left_from -= 1;
1512  n_left_to_next -= 1;
1513  b0 = vlib_get_buffer (vm, bi0);
1514 
1515  sl0 =
1517  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1519  vec_len (sl0->rewrite));
1520 
1521  ip0_encap = vlib_buffer_get_current (b0);
1522 
1523  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1524  sl0->rewrite, vec_len (sl0->rewrite));
1525  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1526 
1527  ip0 = vlib_buffer_get_current (b0);
1528 
1529  encaps_processing_v4 (node, b0, ip0, ip0_encap);
1530 
1531  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1533  {
1535  vlib_add_trace (vm, node, b0, sizeof (*tr));
1536  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1537  sizeof (tr->src.as_u8));
1538  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1539  sizeof (tr->dst.as_u8));
1540  }
1541 
1542  encap_pkts++;
1543  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1544  n_left_to_next, bi0, next0);
1545  }
1546 
1547  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1548  }
1549 
1550  /* Update counters */
1552  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1553  encap_pkts);
1555  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1556  bsid_pkts);
1557 
1558  return from_frame->n_vectors;
1559 }
1560 
1561 /* *INDENT-OFF* */
1563  .function = sr_policy_rewrite_encaps_v4,
1564  .name = "sr-pl-rewrite-encaps-v4",
1565  .vector_size = sizeof (u32),
1566  .format_trace = format_sr_policy_rewrite_trace,
1567  .type = VLIB_NODE_TYPE_INTERNAL,
1568  .n_errors = SR_POLICY_REWRITE_N_ERROR,
1569  .error_strings = sr_policy_rewrite_error_strings,
1570  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1571  .next_nodes = {
1572 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1574 #undef _
1575  },
1576 };
1577 /* *INDENT-ON* */
1578 
1580 ip_flow_hash (void *data)
1581 {
1582  ip4_header_t *iph = (ip4_header_t *) data;
1583 
1584  if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1586  else
1588 }
1589 
1592 {
1593  return (*((u64 *) m) & 0xffffffffffff);
1594 }
1595 
1598 {
1599  ethernet_header_t *eh;
1600  u64 a, b, c;
1601  uword is_ip, eh_size;
1602  u16 eh_type;
1603 
1604  eh = vlib_buffer_get_current (b0);
1605  eh_type = clib_net_to_host_u16 (eh->type);
1606  eh_size = ethernet_buffer_header_size (b0);
1607 
1608  is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1609 
1610  /* since we have 2 cache lines, use them */
1611  if (is_ip)
1612  a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1613  else
1614  a = eh->type;
1615 
1616  b = mac_to_u64 ((u8 *) eh->dst_address);
1617  c = mac_to_u64 ((u8 *) eh->src_address);
1618  hash_mix64 (a, b, c);
1619 
1620  return (u32) c;
1621 }
1622 
1623 /**
1624  * @brief Graph node for applying a SR policy into a L2 frame
1625  */
1626 static uword
1628  vlib_frame_t * from_frame)
1629 {
1630  ip6_sr_main_t *sm = &sr_main;
1631  u32 n_left_from, next_index, *from, *to_next;
1632 
1633  from = vlib_frame_vector_args (from_frame);
1634  n_left_from = from_frame->n_vectors;
1635 
1636  next_index = node->cached_next_index;
1637 
1638  int encap_pkts = 0, bsid_pkts = 0;
1639 
1640  while (n_left_from > 0)
1641  {
1642  u32 n_left_to_next;
1643 
1644  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1645 
1646  /* Quad - Loop */
1647  while (n_left_from >= 8 && n_left_to_next >= 4)
1648  {
1649  u32 bi0, bi1, bi2, bi3;
1650  vlib_buffer_t *b0, *b1, *b2, *b3;
1651  u32 next0, next1, next2, next3;
1652  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1653  ethernet_header_t *en0, *en1, *en2, *en3;
1654  ip6_header_t *ip0, *ip1, *ip2, *ip3;
1655  ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1656  ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1657  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1658 
1659  /* Prefetch next iteration. */
1660  {
1661  vlib_buffer_t *p4, *p5, *p6, *p7;
1662 
1663  p4 = vlib_get_buffer (vm, from[4]);
1664  p5 = vlib_get_buffer (vm, from[5]);
1665  p6 = vlib_get_buffer (vm, from[6]);
1666  p7 = vlib_get_buffer (vm, from[7]);
1667 
1668  /* Prefetch the buffer header and packet for the N+2 loop iteration */
1669  vlib_prefetch_buffer_header (p4, LOAD);
1670  vlib_prefetch_buffer_header (p5, LOAD);
1671  vlib_prefetch_buffer_header (p6, LOAD);
1672  vlib_prefetch_buffer_header (p7, LOAD);
1673 
1678  }
1679 
1680  to_next[0] = bi0 = from[0];
1681  to_next[1] = bi1 = from[1];
1682  to_next[2] = bi2 = from[2];
1683  to_next[3] = bi3 = from[3];
1684  from += 4;
1685  to_next += 4;
1686  n_left_from -= 4;
1687  n_left_to_next -= 4;
1688 
1689  b0 = vlib_get_buffer (vm, bi0);
1690  b1 = vlib_get_buffer (vm, bi1);
1691  b2 = vlib_get_buffer (vm, bi2);
1692  b3 = vlib_get_buffer (vm, bi3);
1693 
1694  sp0 = pool_elt_at_index (sm->sr_policies,
1696  (b0)->sw_if_index
1697  [VLIB_RX]]);
1698 
1699  sp1 = pool_elt_at_index (sm->sr_policies,
1701  (b1)->sw_if_index
1702  [VLIB_RX]]);
1703 
1704  sp2 = pool_elt_at_index (sm->sr_policies,
1706  (b2)->sw_if_index
1707  [VLIB_RX]]);
1708 
1709  sp3 = pool_elt_at_index (sm->sr_policies,
1711  (b3)->sw_if_index
1712  [VLIB_RX]]);
1713 
1714  if (vec_len (sp0->segments_lists) == 1)
1715  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1716  else
1717  {
1718  vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1719  vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1720  sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1721  (vec_len (sp0->segments_lists) - 1))];
1722  }
1723 
1724  if (vec_len (sp1->segments_lists) == 1)
1725  vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1726  else
1727  {
1728  vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1729  vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1730  sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1731  (vec_len (sp1->segments_lists) - 1))];
1732  }
1733 
1734  if (vec_len (sp2->segments_lists) == 1)
1735  vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1736  else
1737  {
1738  vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1739  vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1740  sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1741  (vec_len (sp2->segments_lists) - 1))];
1742  }
1743 
1744  if (vec_len (sp3->segments_lists) == 1)
1745  vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1746  else
1747  {
1748  vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1749  vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1750  sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1751  (vec_len (sp3->segments_lists) - 1))];
1752  }
1753 
1754  sl0 =
1756  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1757  sl1 =
1759  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1760  sl2 =
1762  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1763  sl3 =
1765  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1766 
1768  vec_len (sl0->rewrite));
1770  vec_len (sl1->rewrite));
1772  vec_len (sl2->rewrite));
1774  vec_len (sl3->rewrite));
1775 
1776  en0 = vlib_buffer_get_current (b0);
1777  en1 = vlib_buffer_get_current (b1);
1778  en2 = vlib_buffer_get_current (b2);
1779  en3 = vlib_buffer_get_current (b3);
1780 
1781  clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1782  vec_len (sl0->rewrite));
1783  clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1784  vec_len (sl1->rewrite));
1785  clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1786  vec_len (sl2->rewrite));
1787  clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1788  vec_len (sl3->rewrite));
1789 
1790  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1791  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1792  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1793  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1794 
1795  ip0 = vlib_buffer_get_current (b0);
1796  ip1 = vlib_buffer_get_current (b1);
1797  ip2 = vlib_buffer_get_current (b2);
1798  ip3 = vlib_buffer_get_current (b3);
1799 
1800  ip0->payload_length =
1801  clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1802  ip1->payload_length =
1803  clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1804  ip2->payload_length =
1805  clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1806  ip3->payload_length =
1807  clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1808 
1809  sr0 = (void *) (ip0 + 1);
1810  sr1 = (void *) (ip1 + 1);
1811  sr2 = (void *) (ip2 + 1);
1812  sr3 = (void *) (ip3 + 1);
1813 
1814  sr0->protocol = sr1->protocol = sr2->protocol = sr3->protocol =
1815  IP_PROTOCOL_IP6_NONXT;
1816 
1817  /* Which Traffic class and flow label do I set ? */
1818  //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1819 
1820  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1821  {
1823  {
1825  vlib_add_trace (vm, node, b0, sizeof (*tr));
1826  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1827  sizeof (tr->src.as_u8));
1828  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1829  sizeof (tr->dst.as_u8));
1830  }
1831 
1833  {
1835  vlib_add_trace (vm, node, b1, sizeof (*tr));
1836  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1837  sizeof (tr->src.as_u8));
1838  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1839  sizeof (tr->dst.as_u8));
1840  }
1841 
1843  {
1845  vlib_add_trace (vm, node, b2, sizeof (*tr));
1846  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1847  sizeof (tr->src.as_u8));
1848  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1849  sizeof (tr->dst.as_u8));
1850  }
1851 
1853  {
1855  vlib_add_trace (vm, node, b3, sizeof (*tr));
1856  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1857  sizeof (tr->src.as_u8));
1858  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1859  sizeof (tr->dst.as_u8));
1860  }
1861  }
1862 
1863  encap_pkts += 4;
1864  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1865  n_left_to_next, bi0, bi1, bi2, bi3,
1866  next0, next1, next2, next3);
1867  }
1868 
1869  /* Single loop for potentially the last three packets */
1870  while (n_left_from > 0 && n_left_to_next > 0)
1871  {
1872  u32 bi0;
1873  vlib_buffer_t *b0;
1874  ip6_header_t *ip0 = 0;
1875  ip6_sr_header_t *sr0;
1876  ethernet_header_t *en0;
1877  ip6_sr_policy_t *sp0;
1878  ip6_sr_sl_t *sl0;
1879  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1880 
1881  bi0 = from[0];
1882  to_next[0] = bi0;
1883  from += 1;
1884  to_next += 1;
1885  n_left_from -= 1;
1886  n_left_to_next -= 1;
1887  b0 = vlib_get_buffer (vm, bi0);
1888 
1889  /* Find the SR policy */
1890  sp0 = pool_elt_at_index (sm->sr_policies,
1892  (b0)->sw_if_index
1893  [VLIB_RX]]);
1894 
1895  /* In case there is more than one SL, LB among them */
1896  if (vec_len (sp0->segments_lists) == 1)
1897  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1898  else
1899  {
1900  vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1901  vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1902  sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1903  (vec_len (sp0->segments_lists) - 1))];
1904  }
1905  sl0 =
1907  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1909  vec_len (sl0->rewrite));
1910 
1911  en0 = vlib_buffer_get_current (b0);
1912 
1913  clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1914  vec_len (sl0->rewrite));
1915 
1916  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1917 
1918  ip0 = vlib_buffer_get_current (b0);
1919 
1920  ip0->payload_length =
1921  clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1922 
1923  sr0 = (void *) (ip0 + 1);
1924  sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1925 
1926  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1928  {
1930  vlib_add_trace (vm, node, b0, sizeof (*tr));
1931  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1932  sizeof (tr->src.as_u8));
1933  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1934  sizeof (tr->dst.as_u8));
1935  }
1936 
1937  encap_pkts++;
1938  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1939  n_left_to_next, bi0, next0);
1940  }
1941 
1942  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1943  }
1944 
1945  /* Update counters */
1947  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1948  encap_pkts);
1950  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1951  bsid_pkts);
1952 
1953  return from_frame->n_vectors;
1954 }
1955 
1956 /* *INDENT-OFF* */
1958  .function = sr_policy_rewrite_encaps_l2,
1959  .name = "sr-pl-rewrite-encaps-l2",
1960  .vector_size = sizeof (u32),
1961  .format_trace = format_sr_policy_rewrite_trace,
1962  .type = VLIB_NODE_TYPE_INTERNAL,
1963  .n_errors = SR_POLICY_REWRITE_N_ERROR,
1964  .error_strings = sr_policy_rewrite_error_strings,
1965  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1966  .next_nodes = {
1967 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1969 #undef _
1970  },
1971 };
1972 /* *INDENT-ON* */
1973 
1974 /**
1975  * @brief Graph node for applying a SR policy into a packet. SRH insertion.
1976  */
1977 static uword
1979  vlib_frame_t * from_frame)
1980 {
1981  ip6_sr_main_t *sm = &sr_main;
1982  u32 n_left_from, next_index, *from, *to_next;
1983 
1984  from = vlib_frame_vector_args (from_frame);
1985  n_left_from = from_frame->n_vectors;
1986 
1987  next_index = node->cached_next_index;
1988 
1989  int insert_pkts = 0, bsid_pkts = 0;
1990 
1991  while (n_left_from > 0)
1992  {
1993  u32 n_left_to_next;
1994 
1995  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1996 
1997  /* Quad - Loop */
1998  while (n_left_from >= 8 && n_left_to_next >= 4)
1999  {
2000  u32 bi0, bi1, bi2, bi3;
2001  vlib_buffer_t *b0, *b1, *b2, *b3;
2002  u32 next0, next1, next2, next3;
2003  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2004  ip6_header_t *ip0, *ip1, *ip2, *ip3;
2005  ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2006  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2007  u16 new_l0, new_l1, new_l2, new_l3;
2008 
2009  /* Prefetch next iteration. */
2010  {
2011  vlib_buffer_t *p4, *p5, *p6, *p7;
2012 
2013  p4 = vlib_get_buffer (vm, from[4]);
2014  p5 = vlib_get_buffer (vm, from[5]);
2015  p6 = vlib_get_buffer (vm, from[6]);
2016  p7 = vlib_get_buffer (vm, from[7]);
2017 
2018  /* Prefetch the buffer header and packet for the N+2 loop iteration */
2019  vlib_prefetch_buffer_header (p4, LOAD);
2020  vlib_prefetch_buffer_header (p5, LOAD);
2021  vlib_prefetch_buffer_header (p6, LOAD);
2022  vlib_prefetch_buffer_header (p7, LOAD);
2023 
2028  }
2029 
2030  to_next[0] = bi0 = from[0];
2031  to_next[1] = bi1 = from[1];
2032  to_next[2] = bi2 = from[2];
2033  to_next[3] = bi3 = from[3];
2034  from += 4;
2035  to_next += 4;
2036  n_left_from -= 4;
2037  n_left_to_next -= 4;
2038 
2039  b0 = vlib_get_buffer (vm, bi0);
2040  b1 = vlib_get_buffer (vm, bi1);
2041  b2 = vlib_get_buffer (vm, bi2);
2042  b3 = vlib_get_buffer (vm, bi3);
2043 
2044  sl0 =
2046  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2047  sl1 =
2049  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2050  sl2 =
2052  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2053  sl3 =
2055  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2057  vec_len (sl0->rewrite));
2059  vec_len (sl1->rewrite));
2061  vec_len (sl2->rewrite));
2063  vec_len (sl3->rewrite));
2064 
2065  ip0 = vlib_buffer_get_current (b0);
2066  ip1 = vlib_buffer_get_current (b1);
2067  ip2 = vlib_buffer_get_current (b2);
2068  ip3 = vlib_buffer_get_current (b3);
2069 
2070  if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2071  sr0 =
2072  (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2073  ip6_ext_header_len (ip0 + 1));
2074  else
2075  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2076 
2077  if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2078  sr1 =
2079  (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2080  ip6_ext_header_len (ip1 + 1));
2081  else
2082  sr1 = (ip6_sr_header_t *) (ip1 + 1);
2083 
2084  if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2085  sr2 =
2086  (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2087  ip6_ext_header_len (ip2 + 1));
2088  else
2089  sr2 = (ip6_sr_header_t *) (ip2 + 1);
2090 
2091  if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2092  sr3 =
2093  (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2094  ip6_ext_header_len (ip3 + 1));
2095  else
2096  sr3 = (ip6_sr_header_t *) (ip3 + 1);
2097 
2098  clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2099  (void *) sr0 - (void *) ip0);
2100  clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2101  (void *) sr1 - (void *) ip1);
2102  clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2103  (void *) sr2 - (void *) ip2);
2104  clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2105  (void *) sr3 - (void *) ip3);
2106 
2107  clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2108  vec_len (sl0->rewrite));
2109  clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2110  vec_len (sl1->rewrite));
2111  clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2112  vec_len (sl2->rewrite));
2113  clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2114  vec_len (sl3->rewrite));
2115 
2116  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2117  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2118  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2119  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2120 
2121  ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2122  ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2123  ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2124  ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2125 
2126  ip0->hop_limit -= 1;
2127  ip1->hop_limit -= 1;
2128  ip2->hop_limit -= 1;
2129  ip3->hop_limit -= 1;
2130 
2131  new_l0 =
2132  clib_net_to_host_u16 (ip0->payload_length) +
2133  vec_len (sl0->rewrite);
2134  new_l1 =
2135  clib_net_to_host_u16 (ip1->payload_length) +
2136  vec_len (sl1->rewrite);
2137  new_l2 =
2138  clib_net_to_host_u16 (ip2->payload_length) +
2139  vec_len (sl2->rewrite);
2140  new_l3 =
2141  clib_net_to_host_u16 (ip3->payload_length) +
2142  vec_len (sl3->rewrite);
2143 
2144  ip0->payload_length = clib_host_to_net_u16 (new_l0);
2145  ip1->payload_length = clib_host_to_net_u16 (new_l1);
2146  ip2->payload_length = clib_host_to_net_u16 (new_l2);
2147  ip3->payload_length = clib_host_to_net_u16 (new_l3);
2148 
2149  sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2150  sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2151  sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2152  sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2153 
2154  sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2155  sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2156  sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2157  sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2158  sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2159  sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2160  sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2161  sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2162 
2163  ip0->dst_address.as_u64[0] =
2164  (sr0->segments + sr0->segments_left)->as_u64[0];
2165  ip0->dst_address.as_u64[1] =
2166  (sr0->segments + sr0->segments_left)->as_u64[1];
2167  ip1->dst_address.as_u64[0] =
2168  (sr1->segments + sr1->segments_left)->as_u64[0];
2169  ip1->dst_address.as_u64[1] =
2170  (sr1->segments + sr1->segments_left)->as_u64[1];
2171  ip2->dst_address.as_u64[0] =
2172  (sr2->segments + sr2->segments_left)->as_u64[0];
2173  ip2->dst_address.as_u64[1] =
2174  (sr2->segments + sr2->segments_left)->as_u64[1];
2175  ip3->dst_address.as_u64[0] =
2176  (sr3->segments + sr3->segments_left)->as_u64[0];
2177  ip3->dst_address.as_u64[1] =
2178  (sr3->segments + sr3->segments_left)->as_u64[1];
2179 
2180  ip6_ext_header_t *ip_ext;
2181  if (ip0 + 1 == (void *) sr0)
2182  {
2183  sr0->protocol = ip0->protocol;
2184  ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2185  }
2186  else
2187  {
2188  ip_ext = (void *) (ip0 + 1);
2189  sr0->protocol = ip_ext->next_hdr;
2190  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2191  }
2192 
2193  if (ip1 + 1 == (void *) sr1)
2194  {
2195  sr1->protocol = ip1->protocol;
2196  ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2197  }
2198  else
2199  {
2200  ip_ext = (void *) (ip2 + 1);
2201  sr2->protocol = ip_ext->next_hdr;
2202  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2203  }
2204 
2205  if (ip2 + 1 == (void *) sr2)
2206  {
2207  sr2->protocol = ip2->protocol;
2208  ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2209  }
2210  else
2211  {
2212  ip_ext = (void *) (ip2 + 1);
2213  sr2->protocol = ip_ext->next_hdr;
2214  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2215  }
2216 
2217  if (ip3 + 1 == (void *) sr3)
2218  {
2219  sr3->protocol = ip3->protocol;
2220  ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2221  }
2222  else
2223  {
2224  ip_ext = (void *) (ip3 + 1);
2225  sr3->protocol = ip_ext->next_hdr;
2226  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2227  }
2228 
2229  insert_pkts += 4;
2230 
2231  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2232  {
2234  {
2236  vlib_add_trace (vm, node, b0, sizeof (*tr));
2237  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2238  sizeof (tr->src.as_u8));
2239  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2240  sizeof (tr->dst.as_u8));
2241  }
2242 
2244  {
2246  vlib_add_trace (vm, node, b1, sizeof (*tr));
2247  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2248  sizeof (tr->src.as_u8));
2249  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2250  sizeof (tr->dst.as_u8));
2251  }
2252 
2254  {
2256  vlib_add_trace (vm, node, b2, sizeof (*tr));
2257  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2258  sizeof (tr->src.as_u8));
2259  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2260  sizeof (tr->dst.as_u8));
2261  }
2262 
2264  {
2266  vlib_add_trace (vm, node, b3, sizeof (*tr));
2267  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2268  sizeof (tr->src.as_u8));
2269  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2270  sizeof (tr->dst.as_u8));
2271  }
2272  }
2273 
2274  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2275  n_left_to_next, bi0, bi1, bi2, bi3,
2276  next0, next1, next2, next3);
2277  }
2278 
2279  /* Single loop for potentially the last three packets */
2280  while (n_left_from > 0 && n_left_to_next > 0)
2281  {
2282  u32 bi0;
2283  vlib_buffer_t *b0;
2284  ip6_header_t *ip0 = 0;
2285  ip6_sr_header_t *sr0 = 0;
2286  ip6_sr_sl_t *sl0;
2287  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2288  u16 new_l0 = 0;
2289 
2290  bi0 = from[0];
2291  to_next[0] = bi0;
2292  from += 1;
2293  to_next += 1;
2294  n_left_from -= 1;
2295  n_left_to_next -= 1;
2296 
2297  b0 = vlib_get_buffer (vm, bi0);
2298  sl0 =
2300  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2302  vec_len (sl0->rewrite));
2303 
2304  ip0 = vlib_buffer_get_current (b0);
2305 
2306  if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2307  sr0 =
2308  (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2309  ip6_ext_header_len (ip0 + 1));
2310  else
2311  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2312 
2313  clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2314  (void *) sr0 - (void *) ip0);
2315  clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2316  vec_len (sl0->rewrite));
2317 
2318  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2319 
2320  ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2321  ip0->hop_limit -= 1;
2322  new_l0 =
2323  clib_net_to_host_u16 (ip0->payload_length) +
2324  vec_len (sl0->rewrite);
2325  ip0->payload_length = clib_host_to_net_u16 (new_l0);
2326 
2327  sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2328  sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2329  sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2330 
2331  ip0->dst_address.as_u64[0] =
2332  (sr0->segments + sr0->segments_left)->as_u64[0];
2333  ip0->dst_address.as_u64[1] =
2334  (sr0->segments + sr0->segments_left)->as_u64[1];
2335 
2336  if (ip0 + 1 == (void *) sr0)
2337  {
2338  sr0->protocol = ip0->protocol;
2339  ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2340  }
2341  else
2342  {
2343  ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2344  sr0->protocol = ip_ext->next_hdr;
2345  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2346  }
2347 
2348  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2350  {
2352  vlib_add_trace (vm, node, b0, sizeof (*tr));
2353  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2354  sizeof (tr->src.as_u8));
2355  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2356  sizeof (tr->dst.as_u8));
2357  }
2358 
2359  insert_pkts++;
2360 
2361  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2362  n_left_to_next, bi0, next0);
2363  }
2364 
2365  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2366  }
2367 
2368  /* Update counters */
2370  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2371  insert_pkts);
2373  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2374  bsid_pkts);
2375  return from_frame->n_vectors;
2376 }
2377 
2378 /* *INDENT-OFF* */
2380  .function = sr_policy_rewrite_insert,
2381  .name = "sr-pl-rewrite-insert",
2382  .vector_size = sizeof (u32),
2383  .format_trace = format_sr_policy_rewrite_trace,
2384  .type = VLIB_NODE_TYPE_INTERNAL,
2385  .n_errors = SR_POLICY_REWRITE_N_ERROR,
2386  .error_strings = sr_policy_rewrite_error_strings,
2387  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2388  .next_nodes = {
2389 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2391 #undef _
2392  },
2393 };
2394 /* *INDENT-ON* */
2395 
2396 /**
2397  * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2398  */
2399 static uword
2401  vlib_frame_t * from_frame)
2402 {
2403  ip6_sr_main_t *sm = &sr_main;
2404  u32 n_left_from, next_index, *from, *to_next;
2405 
2406  from = vlib_frame_vector_args (from_frame);
2407  n_left_from = from_frame->n_vectors;
2408 
2409  next_index = node->cached_next_index;
2410 
2411  int insert_pkts = 0, bsid_pkts = 0;
2412 
2413  while (n_left_from > 0)
2414  {
2415  u32 n_left_to_next;
2416 
2417  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2418 
2419  /* Quad - Loop */
2420  while (n_left_from >= 8 && n_left_to_next >= 4)
2421  {
2422  u32 bi0, bi1, bi2, bi3;
2423  vlib_buffer_t *b0, *b1, *b2, *b3;
2424  u32 next0, next1, next2, next3;
2425  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2426  ip6_header_t *ip0, *ip1, *ip2, *ip3;
2427  ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2428  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2429  u16 new_l0, new_l1, new_l2, new_l3;
2430 
2431  /* Prefetch next iteration. */
2432  {
2433  vlib_buffer_t *p4, *p5, *p6, *p7;
2434 
2435  p4 = vlib_get_buffer (vm, from[4]);
2436  p5 = vlib_get_buffer (vm, from[5]);
2437  p6 = vlib_get_buffer (vm, from[6]);
2438  p7 = vlib_get_buffer (vm, from[7]);
2439 
2440  /* Prefetch the buffer header and packet for the N+2 loop iteration */
2441  vlib_prefetch_buffer_header (p4, LOAD);
2442  vlib_prefetch_buffer_header (p5, LOAD);
2443  vlib_prefetch_buffer_header (p6, LOAD);
2444  vlib_prefetch_buffer_header (p7, LOAD);
2445 
2450  }
2451 
2452  to_next[0] = bi0 = from[0];
2453  to_next[1] = bi1 = from[1];
2454  to_next[2] = bi2 = from[2];
2455  to_next[3] = bi3 = from[3];
2456  from += 4;
2457  to_next += 4;
2458  n_left_from -= 4;
2459  n_left_to_next -= 4;
2460 
2461  b0 = vlib_get_buffer (vm, bi0);
2462  b1 = vlib_get_buffer (vm, bi1);
2463  b2 = vlib_get_buffer (vm, bi2);
2464  b3 = vlib_get_buffer (vm, bi3);
2465 
2466  sl0 =
2468  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2469  sl1 =
2471  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2472  sl2 =
2474  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2475  sl3 =
2477  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2479  vec_len (sl0->rewrite_bsid));
2481  vec_len (sl1->rewrite_bsid));
2483  vec_len (sl2->rewrite_bsid));
2485  vec_len (sl3->rewrite_bsid));
2486 
2487  ip0 = vlib_buffer_get_current (b0);
2488  ip1 = vlib_buffer_get_current (b1);
2489  ip2 = vlib_buffer_get_current (b2);
2490  ip3 = vlib_buffer_get_current (b3);
2491 
2492  if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2493  sr0 =
2494  (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2495  ip6_ext_header_len (ip0 + 1));
2496  else
2497  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2498 
2499  if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2500  sr1 =
2501  (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2502  ip6_ext_header_len (ip1 + 1));
2503  else
2504  sr1 = (ip6_sr_header_t *) (ip1 + 1);
2505 
2506  if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2507  sr2 =
2508  (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2509  ip6_ext_header_len (ip2 + 1));
2510  else
2511  sr2 = (ip6_sr_header_t *) (ip2 + 1);
2512 
2513  if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2514  sr3 =
2515  (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2516  ip6_ext_header_len (ip3 + 1));
2517  else
2518  sr3 = (ip6_sr_header_t *) (ip3 + 1);
2519 
2520  clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2521  (void *) sr0 - (void *) ip0);
2522  clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2523  (void *) sr1 - (void *) ip1);
2524  clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2525  (void *) sr2 - (void *) ip2);
2526  clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2527  (void *) sr3 - (void *) ip3);
2528 
2529  clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2530  sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2531  clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2532  sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2533  clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2534  sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2535  clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2536  sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2537 
2538  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2539  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2540  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2541  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2542 
2543  ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2544  ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2545  ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2546  ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2547 
2548  ip0->hop_limit -= 1;
2549  ip1->hop_limit -= 1;
2550  ip2->hop_limit -= 1;
2551  ip3->hop_limit -= 1;
2552 
2553  new_l0 =
2554  clib_net_to_host_u16 (ip0->payload_length) +
2555  vec_len (sl0->rewrite_bsid);
2556  new_l1 =
2557  clib_net_to_host_u16 (ip1->payload_length) +
2558  vec_len (sl1->rewrite_bsid);
2559  new_l2 =
2560  clib_net_to_host_u16 (ip2->payload_length) +
2561  vec_len (sl2->rewrite_bsid);
2562  new_l3 =
2563  clib_net_to_host_u16 (ip3->payload_length) +
2564  vec_len (sl3->rewrite_bsid);
2565 
2566  ip0->payload_length = clib_host_to_net_u16 (new_l0);
2567  ip1->payload_length = clib_host_to_net_u16 (new_l1);
2568  ip2->payload_length = clib_host_to_net_u16 (new_l2);
2569  ip3->payload_length = clib_host_to_net_u16 (new_l3);
2570 
2571  sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2572  sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2573  sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2574  sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2575 
2576  ip0->dst_address.as_u64[0] =
2577  (sr0->segments + sr0->segments_left)->as_u64[0];
2578  ip0->dst_address.as_u64[1] =
2579  (sr0->segments + sr0->segments_left)->as_u64[1];
2580  ip1->dst_address.as_u64[0] =
2581  (sr1->segments + sr1->segments_left)->as_u64[0];
2582  ip1->dst_address.as_u64[1] =
2583  (sr1->segments + sr1->segments_left)->as_u64[1];
2584  ip2->dst_address.as_u64[0] =
2585  (sr2->segments + sr2->segments_left)->as_u64[0];
2586  ip2->dst_address.as_u64[1] =
2587  (sr2->segments + sr2->segments_left)->as_u64[1];
2588  ip3->dst_address.as_u64[0] =
2589  (sr3->segments + sr3->segments_left)->as_u64[0];
2590  ip3->dst_address.as_u64[1] =
2591  (sr3->segments + sr3->segments_left)->as_u64[1];
2592 
2593  ip6_ext_header_t *ip_ext;
2594  if (ip0 + 1 == (void *) sr0)
2595  {
2596  sr0->protocol = ip0->protocol;
2597  ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2598  }
2599  else
2600  {
2601  ip_ext = (void *) (ip0 + 1);
2602  sr0->protocol = ip_ext->next_hdr;
2603  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2604  }
2605 
2606  if (ip1 + 1 == (void *) sr1)
2607  {
2608  sr1->protocol = ip1->protocol;
2609  ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2610  }
2611  else
2612  {
2613  ip_ext = (void *) (ip2 + 1);
2614  sr2->protocol = ip_ext->next_hdr;
2615  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2616  }
2617 
2618  if (ip2 + 1 == (void *) sr2)
2619  {
2620  sr2->protocol = ip2->protocol;
2621  ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2622  }
2623  else
2624  {
2625  ip_ext = (void *) (ip2 + 1);
2626  sr2->protocol = ip_ext->next_hdr;
2627  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2628  }
2629 
2630  if (ip3 + 1 == (void *) sr3)
2631  {
2632  sr3->protocol = ip3->protocol;
2633  ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2634  }
2635  else
2636  {
2637  ip_ext = (void *) (ip3 + 1);
2638  sr3->protocol = ip_ext->next_hdr;
2639  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2640  }
2641 
2642  insert_pkts += 4;
2643 
2644  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2645  {
2647  {
2649  vlib_add_trace (vm, node, b0, sizeof (*tr));
2650  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2651  sizeof (tr->src.as_u8));
2652  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2653  sizeof (tr->dst.as_u8));
2654  }
2655 
2657  {
2659  vlib_add_trace (vm, node, b1, sizeof (*tr));
2660  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2661  sizeof (tr->src.as_u8));
2662  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2663  sizeof (tr->dst.as_u8));
2664  }
2665 
2667  {
2669  vlib_add_trace (vm, node, b2, sizeof (*tr));
2670  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2671  sizeof (tr->src.as_u8));
2672  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2673  sizeof (tr->dst.as_u8));
2674  }
2675 
2677  {
2679  vlib_add_trace (vm, node, b3, sizeof (*tr));
2680  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2681  sizeof (tr->src.as_u8));
2682  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2683  sizeof (tr->dst.as_u8));
2684  }
2685  }
2686 
2687  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2688  n_left_to_next, bi0, bi1, bi2, bi3,
2689  next0, next1, next2, next3);
2690  }
2691 
2692  /* Single loop for potentially the last three packets */
2693  while (n_left_from > 0 && n_left_to_next > 0)
2694  {
2695  u32 bi0;
2696  vlib_buffer_t *b0;
2697  ip6_header_t *ip0 = 0;
2698  ip6_sr_header_t *sr0 = 0;
2699  ip6_sr_sl_t *sl0;
2700  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2701  u16 new_l0 = 0;
2702 
2703  bi0 = from[0];
2704  to_next[0] = bi0;
2705  from += 1;
2706  to_next += 1;
2707  n_left_from -= 1;
2708  n_left_to_next -= 1;
2709 
2710  b0 = vlib_get_buffer (vm, bi0);
2711  sl0 =
2713  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2715  vec_len (sl0->rewrite_bsid));
2716 
2717  ip0 = vlib_buffer_get_current (b0);
2718 
2719  if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2720  sr0 =
2721  (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2722  ip6_ext_header_len (ip0 + 1));
2723  else
2724  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2725 
2726  clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2727  (void *) sr0 - (void *) ip0);
2728  clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2729  sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2730 
2731  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2732 
2733  ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2734  ip0->hop_limit -= 1;
2735  new_l0 =
2736  clib_net_to_host_u16 (ip0->payload_length) +
2737  vec_len (sl0->rewrite_bsid);
2738  ip0->payload_length = clib_host_to_net_u16 (new_l0);
2739 
2740  sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2741 
2742  ip0->dst_address.as_u64[0] =
2743  (sr0->segments + sr0->segments_left)->as_u64[0];
2744  ip0->dst_address.as_u64[1] =
2745  (sr0->segments + sr0->segments_left)->as_u64[1];
2746 
2747  if (ip0 + 1 == (void *) sr0)
2748  {
2749  sr0->protocol = ip0->protocol;
2750  ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2751  }
2752  else
2753  {
2754  ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2755  sr0->protocol = ip_ext->next_hdr;
2756  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2757  }
2758 
2759  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2761  {
2763  vlib_add_trace (vm, node, b0, sizeof (*tr));
2764  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2765  sizeof (tr->src.as_u8));
2766  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2767  sizeof (tr->dst.as_u8));
2768  }
2769 
2770  insert_pkts++;
2771 
2772  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2773  n_left_to_next, bi0, next0);
2774  }
2775 
2776  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2777  }
2778 
2779  /* Update counters */
2781  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2782  insert_pkts);
2784  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2785  bsid_pkts);
2786  return from_frame->n_vectors;
2787 }
2788 
2789 /* *INDENT-OFF* */
2791  .function = sr_policy_rewrite_b_insert,
2792  .name = "sr-pl-rewrite-b-insert",
2793  .vector_size = sizeof (u32),
2794  .format_trace = format_sr_policy_rewrite_trace,
2795  .type = VLIB_NODE_TYPE_INTERNAL,
2796  .n_errors = SR_POLICY_REWRITE_N_ERROR,
2797  .error_strings = sr_policy_rewrite_error_strings,
2798  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2799  .next_nodes = {
2800 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2802 #undef _
2803  },
2804 };
2805 /* *INDENT-ON* */
2806 
2807 /**
2808  * @brief Function BSID encapsulation
2809  */
2812  vlib_buffer_t * b0,
2813  ip6_header_t * ip0,
2814  ip6_sr_header_t * sr0, u32 * next0)
2815 {
2816  ip6_address_t *new_dst0;
2817 
2818  if (PREDICT_FALSE (!sr0))
2819  goto error_bsid_encaps;
2820 
2822  {
2823  if (PREDICT_TRUE (sr0->segments_left != 0))
2824  {
2825  sr0->segments_left -= 1;
2826  new_dst0 = (ip6_address_t *) (sr0->segments);
2827  new_dst0 += sr0->segments_left;
2828  ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2829  ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2830  return;
2831  }
2832  }
2833 
2834 error_bsid_encaps:
2835  *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2836  b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2837 }
2838 
2839 /**
2840  * @brief Graph node for applying a SR policy BSID - Encapsulation
2841  */
2842 static uword
2844  vlib_frame_t * from_frame)
2845 {
2846  ip6_sr_main_t *sm = &sr_main;
2847  u32 n_left_from, next_index, *from, *to_next;
2848 
2849  from = vlib_frame_vector_args (from_frame);
2850  n_left_from = from_frame->n_vectors;
2851 
2852  next_index = node->cached_next_index;
2853 
2854  int encap_pkts = 0, bsid_pkts = 0;
2855 
2856  while (n_left_from > 0)
2857  {
2858  u32 n_left_to_next;
2859 
2860  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2861 
2862  /* Quad - Loop */
2863  while (n_left_from >= 8 && n_left_to_next >= 4)
2864  {
2865  u32 bi0, bi1, bi2, bi3;
2866  vlib_buffer_t *b0, *b1, *b2, *b3;
2867  u32 next0, next1, next2, next3;
2868  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2869  ip6_header_t *ip0, *ip1, *ip2, *ip3;
2870  ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2871  ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2872  ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2873  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2874 
2875  /* Prefetch next iteration. */
2876  {
2877  vlib_buffer_t *p4, *p5, *p6, *p7;
2878 
2879  p4 = vlib_get_buffer (vm, from[4]);
2880  p5 = vlib_get_buffer (vm, from[5]);
2881  p6 = vlib_get_buffer (vm, from[6]);
2882  p7 = vlib_get_buffer (vm, from[7]);
2883 
2884  /* Prefetch the buffer header and packet for the N+2 loop iteration */
2885  vlib_prefetch_buffer_header (p4, LOAD);
2886  vlib_prefetch_buffer_header (p5, LOAD);
2887  vlib_prefetch_buffer_header (p6, LOAD);
2888  vlib_prefetch_buffer_header (p7, LOAD);
2889 
2894  }
2895 
2896  to_next[0] = bi0 = from[0];
2897  to_next[1] = bi1 = from[1];
2898  to_next[2] = bi2 = from[2];
2899  to_next[3] = bi3 = from[3];
2900  from += 4;
2901  to_next += 4;
2902  n_left_from -= 4;
2903  n_left_to_next -= 4;
2904 
2905  b0 = vlib_get_buffer (vm, bi0);
2906  b1 = vlib_get_buffer (vm, bi1);
2907  b2 = vlib_get_buffer (vm, bi2);
2908  b3 = vlib_get_buffer (vm, bi3);
2909 
2910  sl0 =
2912  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2913  sl1 =
2915  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2916  sl2 =
2918  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2919  sl3 =
2921  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2923  vec_len (sl0->rewrite));
2925  vec_len (sl1->rewrite));
2927  vec_len (sl2->rewrite));
2929  vec_len (sl3->rewrite));
2930 
2931  ip0_encap = vlib_buffer_get_current (b0);
2932  ip1_encap = vlib_buffer_get_current (b1);
2933  ip2_encap = vlib_buffer_get_current (b2);
2934  ip3_encap = vlib_buffer_get_current (b3);
2935 
2936  ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2937  IP_PROTOCOL_IPV6_ROUTE);
2938  ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2939  IP_PROTOCOL_IPV6_ROUTE);
2940  ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2941  IP_PROTOCOL_IPV6_ROUTE);
2942  ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2943  IP_PROTOCOL_IPV6_ROUTE);
2944 
2945  end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2946  end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2947  end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2948  end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2949 
2950  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
2951  sl0->rewrite, vec_len (sl0->rewrite));
2952  clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
2953  sl1->rewrite, vec_len (sl1->rewrite));
2954  clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
2955  sl2->rewrite, vec_len (sl2->rewrite));
2956  clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
2957  sl3->rewrite, vec_len (sl3->rewrite));
2958 
2959  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2960  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2961  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2962  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2963 
2964  ip0 = vlib_buffer_get_current (b0);
2965  ip1 = vlib_buffer_get_current (b1);
2966  ip2 = vlib_buffer_get_current (b2);
2967  ip3 = vlib_buffer_get_current (b3);
2968 
2969  encaps_processing_v6 (node, b0, ip0, ip0_encap);
2970  encaps_processing_v6 (node, b1, ip1, ip1_encap);
2971  encaps_processing_v6 (node, b2, ip2, ip2_encap);
2972  encaps_processing_v6 (node, b3, ip3, ip3_encap);
2973 
2974  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2975  {
2977  {
2979  vlib_add_trace (vm, node, b0, sizeof (*tr));
2980  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2981  sizeof (tr->src.as_u8));
2982  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2983  sizeof (tr->dst.as_u8));
2984  }
2985 
2987  {
2989  vlib_add_trace (vm, node, b1, sizeof (*tr));
2990  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2991  sizeof (tr->src.as_u8));
2992  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2993  sizeof (tr->dst.as_u8));
2994  }
2995 
2997  {
2999  vlib_add_trace (vm, node, b2, sizeof (*tr));
3000  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3001  sizeof (tr->src.as_u8));
3002  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3003  sizeof (tr->dst.as_u8));
3004  }
3005 
3007  {
3009  vlib_add_trace (vm, node, b3, sizeof (*tr));
3010  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3011  sizeof (tr->src.as_u8));
3012  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3013  sizeof (tr->dst.as_u8));
3014  }
3015  }
3016 
3017  encap_pkts += 4;
3018  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3019  n_left_to_next, bi0, bi1, bi2, bi3,
3020  next0, next1, next2, next3);
3021  }
3022 
3023  /* Single loop for potentially the last three packets */
3024  while (n_left_from > 0 && n_left_to_next > 0)
3025  {
3026  u32 bi0;
3027  vlib_buffer_t *b0;
3028  ip6_header_t *ip0 = 0, *ip0_encap = 0;
3029  ip6_ext_header_t *prev0;
3030  ip6_sr_header_t *sr0;
3031  ip6_sr_sl_t *sl0;
3032  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3033 
3034  bi0 = from[0];
3035  to_next[0] = bi0;
3036  from += 1;
3037  to_next += 1;
3038  n_left_from -= 1;
3039  n_left_to_next -= 1;
3040  b0 = vlib_get_buffer (vm, bi0);
3041 
3042  sl0 =
3044  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3046  vec_len (sl0->rewrite));
3047 
3048  ip0_encap = vlib_buffer_get_current (b0);
3049  ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3050  IP_PROTOCOL_IPV6_ROUTE);
3051  end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3052 
3053  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3054  sl0->rewrite, vec_len (sl0->rewrite));
3055  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3056 
3057  ip0 = vlib_buffer_get_current (b0);
3058 
3059  encaps_processing_v6 (node, b0, ip0, ip0_encap);
3060 
3061  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3063  {
3065  vlib_add_trace (vm, node, b0, sizeof (*tr));
3066  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3067  sizeof (tr->src.as_u8));
3068  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3069  sizeof (tr->dst.as_u8));
3070  }
3071 
3072  encap_pkts++;
3073  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3074  n_left_to_next, bi0, next0);
3075  }
3076 
3077  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3078  }
3079 
3080  /* Update counters */
3082  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3083  encap_pkts);
3085  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3086  bsid_pkts);
3087 
3088  return from_frame->n_vectors;
3089 }
3090 
3091 /* *INDENT-OFF* */
3093  .function = sr_policy_rewrite_b_encaps,
3094  .name = "sr-pl-rewrite-b-encaps",
3095  .vector_size = sizeof (u32),
3096  .format_trace = format_sr_policy_rewrite_trace,
3097  .type = VLIB_NODE_TYPE_INTERNAL,
3098  .n_errors = SR_POLICY_REWRITE_N_ERROR,
3099  .error_strings = sr_policy_rewrite_error_strings,
3100  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3101  .next_nodes = {
3102 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3104 #undef _
3105  },
3106 };
3107 /* *INDENT-ON* */
3108 
3109 /*************************** SR Segment Lists DPOs ****************************/
3110 static u8 *
3111 format_sr_segment_list_dpo (u8 * s, va_list * args)
3112 {
3113  ip6_sr_main_t *sm = &sr_main;
3115  ip6_sr_sl_t *sl;
3116 
3117  index_t index = va_arg (*args, index_t);
3118  CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3119  s = format (s, "SR: Segment List index:[%d]", index);
3120  s = format (s, "\n\tSegments:");
3121 
3122  sl = pool_elt_at_index (sm->sid_lists, index);
3123 
3124  s = format (s, "< ");
3125  vec_foreach (addr, sl->segments)
3126  {
3127  s = format (s, "%U, ", format_ip6_address, addr);
3128  }
3129  s = format (s, "\b\b > - ");
3130  s = format (s, "Weight: %u", sl->weight);
3131 
3132  return s;
3133 }
3134 
3135 const static dpo_vft_t sr_policy_rewrite_vft = {
3136  .dv_lock = sr_dpo_lock,
3137  .dv_unlock = sr_dpo_unlock,
3138  .dv_format = format_sr_segment_list_dpo,
3139 };
3140 
3141 const static char *const sr_pr_encaps_ip6_nodes[] = {
3142  "sr-pl-rewrite-encaps",
3143  NULL,
3144 };
3145 
3146 const static char *const sr_pr_encaps_ip4_nodes[] = {
3147  "sr-pl-rewrite-encaps-v4",
3148  NULL,
3149 };
3150 
3151 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3154 };
3155 
3156 const static char *const sr_pr_insert_ip6_nodes[] = {
3157  "sr-pl-rewrite-insert",
3158  NULL,
3159 };
3160 
3161 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3163 };
3164 
3165 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3166  "sr-pl-rewrite-b-insert",
3167  NULL,
3168 };
3169 
3170 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3172 };
3173 
3174 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3175  "sr-pl-rewrite-b-encaps",
3176  NULL,
3177 };
3178 
3179 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3181 };
3182 
3183 /********************* SR Policy Rewrite initialization ***********************/
3184 /**
3185  * @brief SR Policy Rewrite initialization
3186  */
3187 clib_error_t *
3189 {
3190  ip6_sr_main_t *sm = &sr_main;
3191 
3192  /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3193  mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3194  sizeof (ip6_address_t));
3195 
3196  /* Init SR VPO DPOs type */
3198  dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3199 
3201  dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3202 
3204  dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3205 
3207  dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3208 
3209  /* Register the L2 encaps node used in HW redirect */
3211 
3212  sm->fib_table_ip6 = (u32) ~ 0;
3213  sm->fib_table_ip4 = (u32) ~ 0;
3214 
3215  return 0;
3216 }
3217 
3219 
3220 
3221 /*
3222 * fd.io coding-style-patch-verification: ON
3223 *
3224 * Local Variables:
3225 * eval: (c-set-style "gnu")
3226 * End:
3227 */
#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.
#define IPv6_DEFAULT_HOP_LIMIT
Definition: sr.h:34
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:1072
static u8 * compute_rewrite_insert(ip6_address_t *sl)
SR rewrite string computation for SRH insertion (inline)
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:341
sr_policy_rewrite_next_t
u8 type
Type (default is 0)
Definition: sr.h:86
#define SR_POLICY_TYPE_DEFAULT
Definition: sr.h:37
#define vec_foreach_index(var, v)
Iterate over vector indices.
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
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:336
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.
#define IPv6_DEFAULT_HEADER_LENGTH
Definition: sr.h:33
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:94
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:191
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:272
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:71
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:62
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]
u32 l2_sr_policy_rewrite_index
Definition: sr.h:192
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
#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:419
#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:210
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:67
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:945
index_t load_balance_create(u32 n_buckets, dpo_proto_t lb_proto, flow_hash_config_t fhc)
Definition: load_balance.c:193
dpo_id_t ip6_dpo
DPO for Encaps/Insert IPv6.
Definition: sr.h:70
u32 * sw_iface_sr_policies
Definition: sr.h:216
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:390
#define always_inline
Definition: clib.h:84
u8 dst_address[6]
Definition: packet.h:53
SR Segment List (SID list)
Definition: sr.h:60
#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:99
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:483
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)
#define SR_POLICY_TYPE_SPRAY
Definition: sr.h:38
u32 fib_table_find(fib_protocol_t proto, u32 table_id)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1025
fib_protocol_t dpo_proto_to_fib(dpo_proto_t dpo_proto)
Definition: fib_types.c:227
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:272
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:1145
vlib_node_registration_t sr_policy_rewrite_b_insert_node
(constructor) VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node)
Definition: fib_entry.h:237
#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
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:391
#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:366
u8 is_encap
Mode (0 is SRH insert, 1 Encaps)
Definition: sr.h:96
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:64
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1131
sr_policy_rewrite_error_t
#define ip6_ext_header_len(p)
Definition: ip6_packet.h:467
unformat_function_t unformat_ip6_address
Definition: format.h:94
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
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:329
#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:345
format_function_t format_ip6_address
Definition: format.h:95
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
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:82
#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:69
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:159
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:460
#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:260
#define IP_FLOW_HASH_DEFAULT
Default: 5-tuple without the "reverse" bit.
Definition: lookup.h:69
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:82
u64 uword
Definition: types.h:112
mhash_t sr_policies_index_hash
Definition: sr.h:201
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 and SR-MPLS.
Definition: fib_entry.h:54
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)
#define SR_SEGMENT_LIST_WEIGHT_DEFAULT
Definition: sr.h:40
ip6_sr_policy_t * sr_policies
Definition: sr.h:198
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:80
u8 * rewrite
Precomputed rewrite header.
Definition: sr.h:66
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:269
dpo_id_t bsid_dpo
SR Policy specific DPO - BSID.
Definition: sr.h:90
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:195
static char * sr_policy_rewrite_error_strings[]
#define vnet_buffer(b)
Definition: buffer.h:304
Segment Routing main datastructure.
Definition: sr.h:189
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:144
dpo_id_t ip6_dpo
SR Policy specific DPO - IPv4.
Definition: sr.h:92
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:205
#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:480
u32 fib_table_ip4
Definition: sr.h:233
u16 flags
Copy of main node flags.
Definition: node.h:454
vhost_vring_addr_t addr
Definition: vhost-user.h:82
u8 ip_version_and_header_length
Definition: ip4_packet.h:132
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
dpo_id_t ip4_dpo
SR Policy specific DPO - IPv6.
Definition: sr.h:91
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:680
u32 fib_table_ip6
Definition: sr.h:232
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:84
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
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.
Segment Routing data structures definitions.
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109