FD.io VPP  v18.01-8-g0eacf49
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 void
117 {
118  clib_memcpy (&sr_pr_encaps_src, address, sizeof (sr_pr_encaps_src));
119 }
120 
121 static clib_error_t *
123  vlib_cli_command_t * cmd)
124 {
126  {
127  if (unformat
128  (input, "addr %U", unformat_ip6_address, &sr_pr_encaps_src))
129  return 0;
130  else
131  return clib_error_return (0, "No address specified");
132  }
133  return clib_error_return (0, "No address specified");
134 }
135 
136 /* *INDENT-OFF* */
137 VLIB_CLI_COMMAND (set_sr_src_command, static) = {
138  .path = "set sr encaps source",
139  .short_help = "set sr encaps source addr <ip6_addr>",
140  .function = set_sr_src_command_fn,
141 };
142 /* *INDENT-ON* */
143 
144 /*********************** SR rewrite string computation ************************/
145 /**
146  * @brief SR rewrite string computation for IPv6 encapsulation (inline)
147  *
148  * @param sl is a vector of IPv6 addresses composing the Segment List
149  *
150  * @return precomputed rewrite string for encapsulation
151  */
152 static inline u8 *
154 {
155  ip6_header_t *iph;
156  ip6_sr_header_t *srh;
157  ip6_address_t *addrp, *this_address;
158  u32 header_length = 0;
159  u8 *rs = NULL;
160 
161  header_length = 0;
162  header_length += IPv6_DEFAULT_HEADER_LENGTH;
163  if (vec_len (sl) > 1)
164  {
165  header_length += sizeof (ip6_sr_header_t);
166  header_length += vec_len (sl) * sizeof (ip6_address_t);
167  }
168 
169  vec_validate (rs, header_length - 1);
170 
171  iph = (ip6_header_t *) rs;
173  clib_host_to_net_u32 (0 | ((6 & 0xF) << 28));
174  iph->src_address.as_u64[0] = sr_pr_encaps_src.as_u64[0];
175  iph->src_address.as_u64[1] = sr_pr_encaps_src.as_u64[1];
176  iph->payload_length = header_length - IPv6_DEFAULT_HEADER_LENGTH;
177  iph->protocol = IP_PROTOCOL_IPV6;
179 
180  if (vec_len (sl) > 1)
181  {
182  srh = (ip6_sr_header_t *) (iph + 1);
183  iph->protocol = IP_PROTOCOL_IPV6_ROUTE;
184  srh->protocol = IP_PROTOCOL_IPV6;
186  srh->segments_left = vec_len (sl) - 1;
187  srh->first_segment = vec_len (sl) - 1;
188  srh->length = ((sizeof (ip6_sr_header_t) +
189  (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
190  srh->flags = 0x00;
191  srh->reserved = 0x00;
192  addrp = srh->segments + vec_len (sl) - 1;
193  vec_foreach (this_address, sl)
194  {
195  clib_memcpy (addrp->as_u8, this_address->as_u8,
196  sizeof (ip6_address_t));
197  addrp--;
198  }
199  }
200 
201  iph->dst_address.as_u64[0] = sl->as_u64[0];
202  iph->dst_address.as_u64[1] = sl->as_u64[1];
203  return rs;
204 }
205 
206 /**
207  * @brief SR rewrite string computation for SRH insertion (inline)
208  *
209  * @param sl is a vector of IPv6 addresses composing the Segment List
210  *
211  * @return precomputed rewrite string for SRH insertion
212  */
213 static inline u8 *
215 {
216  ip6_sr_header_t *srh;
217  ip6_address_t *addrp, *this_address;
218  u32 header_length = 0;
219  u8 *rs = NULL;
220 
221  header_length = 0;
222  header_length += sizeof (ip6_sr_header_t);
223  header_length += (vec_len (sl) + 1) * sizeof (ip6_address_t);
224 
225  vec_validate (rs, header_length - 1);
226 
227  srh = (ip6_sr_header_t *) rs;
229  srh->segments_left = vec_len (sl);
230  srh->first_segment = vec_len (sl);
231  srh->length = ((sizeof (ip6_sr_header_t) +
232  ((vec_len (sl) + 1) * sizeof (ip6_address_t))) / 8) - 1;
233  srh->flags = 0x00;
234  srh->reserved = 0x0000;
235  addrp = srh->segments + vec_len (sl);
236  vec_foreach (this_address, sl)
237  {
238  clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
239  addrp--;
240  }
241  return rs;
242 }
243 
244 /**
245  * @brief SR rewrite string computation for SRH insertion with BSID (inline)
246  *
247  * @param sl is a vector of IPv6 addresses composing the Segment List
248  *
249  * @return precomputed rewrite string for SRH insertion with BSID
250  */
251 static inline u8 *
253 {
254  ip6_sr_header_t *srh;
255  ip6_address_t *addrp, *this_address;
256  u32 header_length = 0;
257  u8 *rs = NULL;
258 
259  header_length = 0;
260  header_length += sizeof (ip6_sr_header_t);
261  header_length += vec_len (sl) * sizeof (ip6_address_t);
262 
263  vec_validate (rs, header_length - 1);
264 
265  srh = (ip6_sr_header_t *) rs;
267  srh->segments_left = vec_len (sl) - 1;
268  srh->first_segment = vec_len (sl) - 1;
269  srh->length = ((sizeof (ip6_sr_header_t) +
270  (vec_len (sl) * sizeof (ip6_address_t))) / 8) - 1;
271  srh->flags = 0x00;
272  srh->reserved = 0x0000;
273  addrp = srh->segments + vec_len (sl) - 1;
274  vec_foreach (this_address, sl)
275  {
276  clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
277  addrp--;
278  }
279  return rs;
280 }
281 
282 /*************************** SR LB helper functions **************************/
283 /**
284  * @brief Creates a Segment List and adds it to an SR policy
285  *
286  * Creates a Segment List and adds it to the SR policy. Notice that the SL are
287  * not necessarily unique. Hence there might be two Segment List within the
288  * same SR Policy with exactly the same segments and same weight.
289  *
290  * @param sr_policy is the SR policy where the SL will be added
291  * @param sl is a vector of IPv6 addresses composing the Segment List
292  * @param weight is the weight of the SegmentList (for load-balancing purposes)
293  * @param is_encap represents the mode (SRH insertion vs Encapsulation)
294  *
295  * @return pointer to the just created segment list
296  */
297 static inline ip6_sr_sl_t *
298 create_sl (ip6_sr_policy_t * sr_policy, ip6_address_t * sl, u32 weight,
299  u8 is_encap)
300 {
301  ip6_sr_main_t *sm = &sr_main;
302  ip6_sr_sl_t *segment_list;
303 
304  pool_get (sm->sid_lists, segment_list);
305  memset (segment_list, 0, sizeof (*segment_list));
306 
307  vec_add1 (sr_policy->segments_lists, segment_list - sm->sid_lists);
308 
309  /* Fill in segment list */
310  segment_list->weight =
311  (weight != (u32) ~ 0 ? weight : SR_SEGMENT_LIST_WEIGHT_DEFAULT);
312  segment_list->segments = vec_dup (sl);
313 
314  if (is_encap)
315  {
316  segment_list->rewrite = compute_rewrite_encaps (sl);
317  segment_list->rewrite_bsid = segment_list->rewrite;
318  }
319  else
320  {
321  segment_list->rewrite = compute_rewrite_insert (sl);
322  segment_list->rewrite_bsid = compute_rewrite_bsid (sl);
323  }
324 
325  /* Create DPO */
326  dpo_reset (&segment_list->bsid_dpo);
327  dpo_reset (&segment_list->ip6_dpo);
328  dpo_reset (&segment_list->ip4_dpo);
329 
330  if (is_encap)
331  {
333  segment_list - sm->sid_lists);
335  segment_list - sm->sid_lists);
337  DPO_PROTO_IP6, segment_list - sm->sid_lists);
338  }
339  else
340  {
342  segment_list - sm->sid_lists);
344  DPO_PROTO_IP6, segment_list - sm->sid_lists);
345  }
346 
347  return segment_list;
348 }
349 
350 /**
351  * @brief Updates the Load Balancer after an SR Policy change
352  *
353  * @param sr_policy is the modified SR Policy
354  */
355 static inline void
357 {
358  flow_hash_config_t fhc;
359  u32 *sl_index;
360  ip6_sr_sl_t *segment_list;
361  ip6_sr_main_t *sm = &sr_main;
362  load_balance_path_t path;
364  load_balance_path_t *ip4_path_vector = 0;
365  load_balance_path_t *ip6_path_vector = 0;
366  load_balance_path_t *b_path_vector = 0;
367 
368  /* In case LB does not exist, create it */
369  if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
370  {
371  fib_prefix_t pfx = {
373  .fp_len = 128,
374  .fp_addr = {
375  .ip6 = sr_policy->bsid,
376  }
377  };
378 
379  /* Add FIB entry for BSID */
380  fhc = fib_table_get_flow_hash_config (sr_policy->fib_table,
382 
385 
388 
389  /* Update FIB entry's to point to the LB DPO in the main FIB and hidden one */
391  sr_policy->fib_table),
392  &pfx, FIB_SOURCE_SR,
394  &sr_policy->bsid_dpo);
395 
397  &pfx,
400  &sr_policy->ip6_dpo);
401 
402  if (sr_policy->is_encap)
403  {
406 
408  &pfx,
411  &sr_policy->ip4_dpo);
412  }
413 
414  }
415 
416  /* Create the LB path vector */
417  //path_vector = vec_new(load_balance_path_t, vec_len(sr_policy->segments_lists));
418  vec_foreach (sl_index, sr_policy->segments_lists)
419  {
420  segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
421  path.path_dpo = segment_list->bsid_dpo;
422  path.path_weight = segment_list->weight;
423  vec_add1 (b_path_vector, path);
424  path.path_dpo = segment_list->ip6_dpo;
425  vec_add1 (ip6_path_vector, path);
426  if (sr_policy->is_encap)
427  {
428  path.path_dpo = segment_list->ip4_dpo;
429  vec_add1 (ip4_path_vector, path);
430  }
431  }
432 
433  /* Update LB multipath */
434  load_balance_multipath_update (&sr_policy->bsid_dpo, b_path_vector,
436  load_balance_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector,
438  if (sr_policy->is_encap)
439  load_balance_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector,
441 
442  /* Cleanup */
443  vec_free (b_path_vector);
444  vec_free (ip6_path_vector);
445  vec_free (ip4_path_vector);
446 
447 }
448 
449 /**
450  * @brief Updates the Replicate DPO after an SR Policy change
451  *
452  * @param sr_policy is the modified SR Policy (type spray)
453  */
454 static inline void
456 {
457  u32 *sl_index;
458  ip6_sr_sl_t *segment_list;
459  ip6_sr_main_t *sm = &sr_main;
460  load_balance_path_t path;
462  load_balance_path_t *b_path_vector = 0;
463  load_balance_path_t *ip6_path_vector = 0;
464  load_balance_path_t *ip4_path_vector = 0;
465 
466  /* In case LB does not exist, create it */
467  if (!dpo_id_is_valid (&sr_policy->bsid_dpo))
468  {
469  dpo_set (&sr_policy->bsid_dpo, DPO_REPLICATE,
471 
472  dpo_set (&sr_policy->ip6_dpo, DPO_REPLICATE,
474 
475  /* Update FIB entry's DPO to point to SR without LB */
476  fib_prefix_t pfx = {
478  .fp_len = 128,
479  .fp_addr = {
480  .ip6 = sr_policy->bsid,
481  }
482  };
484  sr_policy->fib_table),
485  &pfx, FIB_SOURCE_SR,
487  &sr_policy->bsid_dpo);
488 
490  &pfx,
493  &sr_policy->ip6_dpo);
494 
495  if (sr_policy->is_encap)
496  {
499 
501  &pfx,
504  &sr_policy->ip4_dpo);
505  }
506 
507  }
508 
509  /* Create the replicate path vector */
510  path.path_weight = 1;
511  vec_foreach (sl_index, sr_policy->segments_lists)
512  {
513  segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
514  path.path_dpo = segment_list->bsid_dpo;
515  vec_add1 (b_path_vector, path);
516  path.path_dpo = segment_list->ip6_dpo;
517  vec_add1 (ip6_path_vector, path);
518  if (sr_policy->is_encap)
519  {
520  path.path_dpo = segment_list->ip4_dpo;
521  vec_add1 (ip4_path_vector, path);
522  }
523  }
524 
525  /* Update replicate multipath */
526  replicate_multipath_update (&sr_policy->bsid_dpo, b_path_vector);
527  replicate_multipath_update (&sr_policy->ip6_dpo, ip6_path_vector);
528  if (sr_policy->is_encap)
529  replicate_multipath_update (&sr_policy->ip4_dpo, ip4_path_vector);
530 }
531 
532 /******************************* SR rewrite API *******************************/
533 /* Three functions for handling sr policies:
534  * -> sr_policy_add
535  * -> sr_policy_del
536  * -> sr_policy_mod
537  * All of them are API. CLI function on sr_policy_command_fn */
538 
539 /**
540  * @brief Create a new SR policy
541  *
542  * @param bsid is the bindingSID of the SR Policy
543  * @param segments is a vector of IPv6 address composing the segment list
544  * @param weight is the weight of the sid list. optional.
545  * @param behavior is the behavior of the SR policy. (default//spray)
546  * @param fib_table is the VRF where to install the FIB entry for the BSID
547  * @param is_encap (bool) whether SR policy should behave as Encap/SRH Insertion
548  *
549  * @return 0 if correct, else error
550  */
551 int
553  u32 weight, u8 behavior, u32 fib_table, u8 is_encap)
554 {
555  ip6_sr_main_t *sm = &sr_main;
556  ip6_sr_policy_t *sr_policy = 0;
557  uword *p;
558 
559  /* Search for existing keys (BSID) */
560  p = mhash_get (&sm->sr_policies_index_hash, bsid);
561  if (p)
562  {
563  /* Add SR policy that already exists; complain */
564  return -12;
565  }
566 
567  /* Search collision in FIB entries */
568  /* Explanation: It might be possible that some other entity has already
569  * created a route for the BSID. This in theory is impossible, but in
570  * practise we could see it. Assert it and scream if needed */
571  fib_prefix_t pfx = {
573  .fp_len = 128,
574  .fp_addr = {
575  .ip6 = *bsid,
576  }
577  };
578 
579  /* Lookup the FIB index associated to the table selected */
580  u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6,
581  (fib_table != (u32) ~ 0 ? fib_table : 0));
582  if (fib_index == ~0)
583  return -13;
584 
585  /* Lookup whether there exists an entry for the BSID */
586  fib_node_index_t fei = fib_table_lookup_exact_match (fib_index, &pfx);
587  if (FIB_NODE_INDEX_INVALID != fei)
588  return -12; //There is an entry for such lookup
589 
590  /* Add an SR policy object */
591  pool_get (sm->sr_policies, sr_policy);
592  memset (sr_policy, 0, sizeof (*sr_policy));
593  clib_memcpy (&sr_policy->bsid, bsid, sizeof (ip6_address_t));
594  sr_policy->type = behavior;
595  sr_policy->fib_table = (fib_table != (u32) ~ 0 ? fib_table : 0); //Is default FIB 0 ?
596  sr_policy->is_encap = is_encap;
597 
598  /* Copy the key */
599  mhash_set (&sm->sr_policies_index_hash, bsid, sr_policy - sm->sr_policies,
600  NULL);
601 
602  /* Create a segment list and add the index to the SR policy */
603  create_sl (sr_policy, segments, weight, is_encap);
604 
605  /* If FIB doesnt exist, create them */
606  if (sm->fib_table_ip6 == (u32) ~ 0)
607  {
610  "SRv6 steering of IP6 prefixes through BSIDs");
613  "SRv6 steering of IP4 prefixes through BSIDs");
614  }
615 
616  /* Create IPv6 FIB for the BindingSID attached to the DPO of the only SL */
617  if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
618  update_lb (sr_policy);
619  else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
620  update_replicate (sr_policy);
621  return 0;
622 }
623 
624 /**
625  * @brief Delete a SR policy
626  *
627  * @param bsid is the bindingSID of the SR Policy
628  * @param index is the index of the SR policy
629  *
630  * @return 0 if correct, else error
631  */
632 int
634 {
635  ip6_sr_main_t *sm = &sr_main;
636  ip6_sr_policy_t *sr_policy = 0;
637  ip6_sr_sl_t *segment_list;
638  u32 *sl_index;
639  uword *p;
640 
641  if (bsid)
642  {
643  p = mhash_get (&sm->sr_policies_index_hash, bsid);
644  if (p)
645  sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
646  else
647  return -1;
648  }
649  else
650  {
651  sr_policy = pool_elt_at_index (sm->sr_policies, index);
652  if (!sr_policy)
653  return -1;
654  }
655 
656  /* Remove BindingSID FIB entry */
657  fib_prefix_t pfx = {
659  .fp_len = 128,
660  .fp_addr = {
661  .ip6 = sr_policy->bsid,
662  }
663  ,
664  };
665 
667  sr_policy->fib_table),
668  &pfx, FIB_SOURCE_SR);
669 
671 
672  if (sr_policy->is_encap)
674 
675  if (dpo_id_is_valid (&sr_policy->bsid_dpo))
676  {
677  dpo_reset (&sr_policy->bsid_dpo);
678  dpo_reset (&sr_policy->ip4_dpo);
679  dpo_reset (&sr_policy->ip6_dpo);
680  }
681 
682  /* Clean SID Lists */
683  vec_foreach (sl_index, sr_policy->segments_lists)
684  {
685  segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
686  vec_free (segment_list->segments);
687  vec_free (segment_list->rewrite);
688  if (!sr_policy->is_encap)
689  vec_free (segment_list->rewrite_bsid);
690  pool_put_index (sm->sid_lists, *sl_index);
691  }
692 
693  /* Remove SR policy entry */
694  mhash_unset (&sm->sr_policies_index_hash, &sr_policy->bsid, NULL);
695  pool_put (sm->sr_policies, sr_policy);
696 
697  /* If FIB empty unlock it */
698  if (!pool_elts (sm->sr_policies) && !pool_elts (sm->steer_policies))
699  {
702  sm->fib_table_ip6 = (u32) ~ 0;
703  sm->fib_table_ip4 = (u32) ~ 0;
704  }
705 
706  return 0;
707 }
708 
709 /**
710  * @brief Modify an existing SR policy
711  *
712  * The possible modifications are adding a new Segment List, modifying an
713  * existing Segment List (modify the weight only) and delete a given
714  * Segment List from the SR Policy.
715  *
716  * @param bsid is the bindingSID of the SR Policy
717  * @param index is the index of the SR policy
718  * @param fib_table is the VRF where to install the FIB entry for the BSID
719  * @param operation is the operation to perform (among the top ones)
720  * @param segments is a vector of IPv6 address composing the segment list
721  * @param sl_index is the index of the Segment List to modify/delete
722  * @param weight is the weight of the sid list. optional.
723  * @param is_encap Mode. Encapsulation or SRH insertion.
724  *
725  * @return 0 if correct, else error
726  */
727 int
728 sr_policy_mod (ip6_address_t * bsid, u32 index, u32 fib_table,
729  u8 operation, ip6_address_t * segments, u32 sl_index,
730  u32 weight)
731 {
732  ip6_sr_main_t *sm = &sr_main;
733  ip6_sr_policy_t *sr_policy = 0;
734  ip6_sr_sl_t *segment_list;
735  u32 *sl_index_iterate;
736  uword *p;
737 
738  if (bsid)
739  {
740  p = mhash_get (&sm->sr_policies_index_hash, bsid);
741  if (p)
742  sr_policy = pool_elt_at_index (sm->sr_policies, p[0]);
743  else
744  return -1;
745  }
746  else
747  {
748  sr_policy = pool_elt_at_index (sm->sr_policies, index);
749  if (!sr_policy)
750  return -1;
751  }
752 
753  if (operation == 1) /* Add SR List to an existing SR policy */
754  {
755  /* Create the new SL */
756  segment_list =
757  create_sl (sr_policy, segments, weight, sr_policy->is_encap);
758 
759  /* Create a new LB DPO */
760  if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
761  update_lb (sr_policy);
762  else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
763  update_replicate (sr_policy);
764  }
765  else if (operation == 2) /* Delete SR List from an existing SR policy */
766  {
767  /* Check that currently there are more than one SID list */
768  if (vec_len (sr_policy->segments_lists) == 1)
769  return -21;
770 
771  /* Check that the SR list does exist and is assigned to the sr policy */
772  vec_foreach (sl_index_iterate, sr_policy->segments_lists)
773  if (*sl_index_iterate == sl_index)
774  break;
775 
776  if (*sl_index_iterate != sl_index)
777  return -22;
778 
779  /* Remove the lucky SR list that is being kicked out */
780  segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
781  vec_free (segment_list->segments);
782  vec_free (segment_list->rewrite);
783  if (!sr_policy->is_encap)
784  vec_free (segment_list->rewrite_bsid);
785  pool_put_index (sm->sid_lists, sl_index);
786  vec_del1 (sr_policy->segments_lists,
787  sl_index_iterate - sr_policy->segments_lists);
788 
789  /* Create a new LB DPO */
790  if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
791  update_lb (sr_policy);
792  else if (sr_policy->type == SR_POLICY_TYPE_SPRAY)
793  update_replicate (sr_policy);
794  }
795  else if (operation == 3) /* Modify the weight of an existing SR List */
796  {
797  /* Find the corresponding SL */
798  vec_foreach (sl_index_iterate, sr_policy->segments_lists)
799  if (*sl_index_iterate == sl_index)
800  break;
801 
802  if (*sl_index_iterate != sl_index)
803  return -32;
804 
805  /* Change the weight */
806  segment_list = pool_elt_at_index (sm->sid_lists, sl_index);
807  segment_list->weight = weight;
808 
809  /* Update LB */
810  if (sr_policy->type == SR_POLICY_TYPE_DEFAULT)
811  update_lb (sr_policy);
812  }
813  else /* Incorrect op. */
814  return -1;
815 
816  return 0;
817 }
818 
819 /**
820  * @brief CLI for 'sr policies' command family
821  */
822 static clib_error_t *
824  vlib_cli_command_t * cmd)
825 {
826  int rv = -1;
827  char is_del = 0, is_add = 0, is_mod = 0;
828  char policy_set = 0;
829  ip6_address_t bsid, next_address;
830  u32 sr_policy_index = (u32) ~ 0, sl_index = (u32) ~ 0;
831  u32 weight = (u32) ~ 0, fib_table = (u32) ~ 0;
832  ip6_address_t *segments = 0, *this_seg;
833  u8 operation = 0;
834  char is_encap = 1;
835  char is_spray = 0;
836 
838  {
839  if (!is_add && !is_mod && !is_del && unformat (input, "add"))
840  is_add = 1;
841  else if (!is_add && !is_mod && !is_del && unformat (input, "del"))
842  is_del = 1;
843  else if (!is_add && !is_mod && !is_del && unformat (input, "mod"))
844  is_mod = 1;
845  else if (!policy_set
846  && unformat (input, "bsid %U", unformat_ip6_address, &bsid))
847  policy_set = 1;
848  else if (!is_add && !policy_set
849  && unformat (input, "index %d", &sr_policy_index))
850  policy_set = 1;
851  else if (unformat (input, "weight %d", &weight));
852  else
853  if (unformat (input, "next %U", unformat_ip6_address, &next_address))
854  {
855  vec_add2 (segments, this_seg, 1);
856  clib_memcpy (this_seg->as_u8, next_address.as_u8,
857  sizeof (*this_seg));
858  }
859  else if (unformat (input, "add sl"))
860  operation = 1;
861  else if (unformat (input, "del sl index %d", &sl_index))
862  operation = 2;
863  else if (unformat (input, "mod sl index %d", &sl_index))
864  operation = 3;
865  else if (fib_table == (u32) ~ 0
866  && unformat (input, "fib-table %d", &fib_table));
867  else if (unformat (input, "encap"))
868  is_encap = 1;
869  else if (unformat (input, "insert"))
870  is_encap = 0;
871  else if (unformat (input, "spray"))
872  is_spray = 1;
873  else
874  break;
875  }
876 
877  if (!is_add && !is_mod && !is_del)
878  return clib_error_return (0, "Incorrect CLI");
879 
880  if (!policy_set)
881  return clib_error_return (0, "No SR policy BSID or index specified");
882 
883  if (is_add)
884  {
885  if (vec_len (segments) == 0)
886  return clib_error_return (0, "No Segment List specified");
887  rv = sr_policy_add (&bsid, segments, weight,
888  (is_spray ? SR_POLICY_TYPE_SPRAY :
889  SR_POLICY_TYPE_DEFAULT), fib_table, is_encap);
890  }
891  else if (is_del)
892  rv = sr_policy_del ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
893  sr_policy_index);
894  else if (is_mod)
895  {
896  if (!operation)
897  return clib_error_return (0, "No SL modification specified");
898  if (operation != 1 && sl_index == (u32) ~ 0)
899  return clib_error_return (0, "No Segment List index specified");
900  if (operation == 1 && vec_len (segments) == 0)
901  return clib_error_return (0, "No Segment List specified");
902  if (operation == 3 && weight == (u32) ~ 0)
903  return clib_error_return (0, "No new weight for the SL specified");
904  rv = sr_policy_mod ((sr_policy_index != (u32) ~ 0 ? NULL : &bsid),
905  sr_policy_index, fib_table, operation, segments,
906  sl_index, weight);
907  }
908 
909  switch (rv)
910  {
911  case 0:
912  break;
913  case 1:
914  return 0;
915  case -12:
916  return clib_error_return (0,
917  "There is already a FIB entry for the BindingSID address.\n"
918  "The SR policy could not be created.");
919  case -13:
920  return clib_error_return (0, "The specified FIB table does not exist.");
921  case -21:
922  return clib_error_return (0,
923  "The selected SR policy only contains ONE segment list. "
924  "Please remove the SR policy instead");
925  case -22:
926  return clib_error_return (0,
927  "Could not delete the segment list. "
928  "It is not associated with that SR policy.");
929  case -32:
930  return clib_error_return (0,
931  "Could not modify the segment list. "
932  "The given SL is not associated with such SR policy.");
933  default:
934  return clib_error_return (0, "BUG: sr policy returns %d", rv);
935  }
936  return 0;
937 }
938 
939 /* *INDENT-OFF* */
940 VLIB_CLI_COMMAND (sr_policy_command, static) = {
941  .path = "sr policy",
942  .short_help = "sr policy [add||del||mod] [bsid 2001::1||index 5] "
943  "next A:: next B:: next C:: (weight 1) (fib-table 2) (encap|insert)",
944  .long_help =
945  "Manipulation of SR policies.\n"
946  "A Segment Routing policy may contain several SID lists. Each SID list has\n"
947  "an associated weight (default 1), which will result in wECMP (uECMP).\n"
948  "Segment Routing policies might be of type encapsulation or srh insertion\n"
949  "Each SR policy will be associated with a unique BindingSID.\n"
950  "A BindingSID is a locally allocated SegmentID. For every packet that arrives\n"
951  "with IPv6_DA:BSID such traffic will be steered into the SR policy.\n"
952  "The add command will create a SR policy with its first segment list (sl)\n"
953  "The mod command allows you to add, remove, or modify the existing segment lists\n"
954  "within an SR policy.\n"
955  "The del command allows you to delete a SR policy along with all its associated\n"
956  "SID lists.\n",
957  .function = sr_policy_command_fn,
958 };
959 /* *INDENT-ON* */
960 
961 /**
962  * @brief CLI to display onscreen all the SR policies
963  */
964 static clib_error_t *
966  vlib_cli_command_t * cmd)
967 {
968  ip6_sr_main_t *sm = &sr_main;
969  u32 *sl_index;
970  ip6_sr_sl_t *segment_list = 0;
971  ip6_sr_policy_t *sr_policy = 0;
972  ip6_sr_policy_t **vec_policies = 0;
974  u8 *s;
975  int i = 0;
976 
977  vlib_cli_output (vm, "SR policies:");
978 
979  /* *INDENT-OFF* */
980  pool_foreach (sr_policy, sm->sr_policies,
981  {vec_add1 (vec_policies, sr_policy); } );
982  /* *INDENT-ON* */
983 
984  vec_foreach_index (i, vec_policies)
985  {
986  sr_policy = vec_policies[i];
987  vlib_cli_output (vm, "[%u].-\tBSID: %U",
988  (u32) (sr_policy - sm->sr_policies),
989  format_ip6_address, &sr_policy->bsid);
990  vlib_cli_output (vm, "\tBehavior: %s",
991  (sr_policy->is_encap ? "Encapsulation" :
992  "SRH insertion"));
993  vlib_cli_output (vm, "\tType: %s",
994  (sr_policy->type ==
995  SR_POLICY_TYPE_DEFAULT ? "Default" : "Spray"));
996  vlib_cli_output (vm, "\tFIB table: %u",
997  (sr_policy->fib_table !=
998  (u32) ~ 0 ? sr_policy->fib_table : 0));
999  vlib_cli_output (vm, "\tSegment Lists:");
1000  vec_foreach (sl_index, sr_policy->segments_lists)
1001  {
1002  s = NULL;
1003  s = format (s, "\t[%u].- ", *sl_index);
1004  segment_list = pool_elt_at_index (sm->sid_lists, *sl_index);
1005  s = format (s, "< ");
1006  vec_foreach (addr, segment_list->segments)
1007  {
1008  s = format (s, "%U, ", format_ip6_address, addr);
1009  }
1010  s = format (s, "\b\b > ");
1011  s = format (s, "weight: %u", segment_list->weight);
1012  vlib_cli_output (vm, " %s", s);
1013  }
1014  vlib_cli_output (vm, "-----------");
1015  }
1016  return 0;
1017 }
1018 
1019 /* *INDENT-OFF* */
1020 VLIB_CLI_COMMAND (show_sr_policies_command, static) = {
1021  .path = "show sr policies",
1022  .short_help = "show sr policies",
1023  .function = show_sr_policies_command_fn,
1024 };
1025 /* *INDENT-ON* */
1026 
1027 /*************************** SR rewrite graph node ****************************/
1028 /**
1029  * @brief Trace for the SR Policy Rewrite graph node
1030  */
1031 static u8 *
1032 format_sr_policy_rewrite_trace (u8 * s, va_list * args)
1033 {
1034  //TODO
1035  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1036  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1038 
1039  s = format
1040  (s, "SR-policy-rewrite: src %U dst %U",
1042 
1043  return s;
1044 }
1045 
1046 /**
1047  * @brief IPv6 encapsulation processing as per RFC2473
1048  */
1051  vlib_buffer_t * b0,
1052  ip6_header_t * ip0, ip6_header_t * ip0_encap)
1053 {
1054  u32 new_l0;
1055 
1056  ip0_encap->hop_limit -= 1;
1057  new_l0 =
1058  ip0->payload_length + sizeof (ip6_header_t) +
1059  clib_net_to_host_u16 (ip0_encap->payload_length);
1060  ip0->payload_length = clib_host_to_net_u16 (new_l0);
1063 }
1064 
1065 /**
1066  * @brief Graph node for applying a SR policy into an IPv6 packet. Encapsulation
1067  */
1068 static uword
1070  vlib_frame_t * from_frame)
1071 {
1072  ip6_sr_main_t *sm = &sr_main;
1073  u32 n_left_from, next_index, *from, *to_next;
1074 
1075  from = vlib_frame_vector_args (from_frame);
1076  n_left_from = from_frame->n_vectors;
1077 
1078  next_index = node->cached_next_index;
1079 
1080  int encap_pkts = 0, bsid_pkts = 0;
1081 
1082  while (n_left_from > 0)
1083  {
1084  u32 n_left_to_next;
1085 
1086  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1087 
1088  /* Quad - Loop */
1089  while (n_left_from >= 8 && n_left_to_next >= 4)
1090  {
1091  u32 bi0, bi1, bi2, bi3;
1092  vlib_buffer_t *b0, *b1, *b2, *b3;
1093  u32 next0, next1, next2, next3;
1094  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1095  ip6_header_t *ip0, *ip1, *ip2, *ip3;
1096  ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1097  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1098 
1099  /* Prefetch next iteration. */
1100  {
1101  vlib_buffer_t *p4, *p5, *p6, *p7;
1102 
1103  p4 = vlib_get_buffer (vm, from[4]);
1104  p5 = vlib_get_buffer (vm, from[5]);
1105  p6 = vlib_get_buffer (vm, from[6]);
1106  p7 = vlib_get_buffer (vm, from[7]);
1107 
1108  /* Prefetch the buffer header and packet for the N+2 loop iteration */
1109  vlib_prefetch_buffer_header (p4, LOAD);
1110  vlib_prefetch_buffer_header (p5, LOAD);
1111  vlib_prefetch_buffer_header (p6, LOAD);
1112  vlib_prefetch_buffer_header (p7, LOAD);
1113 
1118  }
1119 
1120  to_next[0] = bi0 = from[0];
1121  to_next[1] = bi1 = from[1];
1122  to_next[2] = bi2 = from[2];
1123  to_next[3] = bi3 = from[3];
1124  from += 4;
1125  to_next += 4;
1126  n_left_from -= 4;
1127  n_left_to_next -= 4;
1128 
1129  b0 = vlib_get_buffer (vm, bi0);
1130  b1 = vlib_get_buffer (vm, bi1);
1131  b2 = vlib_get_buffer (vm, bi2);
1132  b3 = vlib_get_buffer (vm, bi3);
1133 
1134  sl0 =
1136  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1137  sl1 =
1139  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1140  sl2 =
1142  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1143  sl3 =
1145  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1146 
1148  vec_len (sl0->rewrite));
1150  vec_len (sl1->rewrite));
1152  vec_len (sl2->rewrite));
1154  vec_len (sl3->rewrite));
1155 
1156  ip0_encap = vlib_buffer_get_current (b0);
1157  ip1_encap = vlib_buffer_get_current (b1);
1158  ip2_encap = vlib_buffer_get_current (b2);
1159  ip3_encap = vlib_buffer_get_current (b3);
1160 
1161  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1162  sl0->rewrite, vec_len (sl0->rewrite));
1163  clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1164  sl1->rewrite, vec_len (sl1->rewrite));
1165  clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1166  sl2->rewrite, vec_len (sl2->rewrite));
1167  clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1168  sl3->rewrite, vec_len (sl3->rewrite));
1169 
1170  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1171  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1172  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1173  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1174 
1175  ip0 = vlib_buffer_get_current (b0);
1176  ip1 = vlib_buffer_get_current (b1);
1177  ip2 = vlib_buffer_get_current (b2);
1178  ip3 = vlib_buffer_get_current (b3);
1179 
1180  encaps_processing_v6 (node, b0, ip0, ip0_encap);
1181  encaps_processing_v6 (node, b1, ip1, ip1_encap);
1182  encaps_processing_v6 (node, b2, ip2, ip2_encap);
1183  encaps_processing_v6 (node, b3, ip3, ip3_encap);
1184 
1185  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1186  {
1188  {
1190  vlib_add_trace (vm, node, b0, sizeof (*tr));
1191  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1192  sizeof (tr->src.as_u8));
1193  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1194  sizeof (tr->dst.as_u8));
1195  }
1196 
1198  {
1200  vlib_add_trace (vm, node, b1, sizeof (*tr));
1201  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1202  sizeof (tr->src.as_u8));
1203  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1204  sizeof (tr->dst.as_u8));
1205  }
1206 
1208  {
1210  vlib_add_trace (vm, node, b2, sizeof (*tr));
1211  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1212  sizeof (tr->src.as_u8));
1213  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1214  sizeof (tr->dst.as_u8));
1215  }
1216 
1218  {
1220  vlib_add_trace (vm, node, b3, sizeof (*tr));
1221  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1222  sizeof (tr->src.as_u8));
1223  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1224  sizeof (tr->dst.as_u8));
1225  }
1226  }
1227 
1228  encap_pkts += 4;
1229  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1230  n_left_to_next, bi0, bi1, bi2, bi3,
1231  next0, next1, next2, next3);
1232  }
1233 
1234  /* Single loop for potentially the last three packets */
1235  while (n_left_from > 0 && n_left_to_next > 0)
1236  {
1237  u32 bi0;
1238  vlib_buffer_t *b0;
1239  ip6_header_t *ip0 = 0, *ip0_encap = 0;
1240  ip6_sr_sl_t *sl0;
1241  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1242 
1243  bi0 = from[0];
1244  to_next[0] = bi0;
1245  from += 1;
1246  to_next += 1;
1247  n_left_from -= 1;
1248  n_left_to_next -= 1;
1249  b0 = vlib_get_buffer (vm, bi0);
1250 
1251  sl0 =
1253  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1255  vec_len (sl0->rewrite));
1256 
1257  ip0_encap = vlib_buffer_get_current (b0);
1258 
1259  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1260  sl0->rewrite, vec_len (sl0->rewrite));
1261  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1262 
1263  ip0 = vlib_buffer_get_current (b0);
1264 
1265  encaps_processing_v6 (node, b0, ip0, ip0_encap);
1266 
1267  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1269  {
1271  vlib_add_trace (vm, node, b0, sizeof (*tr));
1272  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1273  sizeof (tr->src.as_u8));
1274  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1275  sizeof (tr->dst.as_u8));
1276  }
1277 
1278  encap_pkts++;
1279  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1280  n_left_to_next, bi0, next0);
1281  }
1282 
1283  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1284  }
1285 
1286  /* Update counters */
1288  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1289  encap_pkts);
1291  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1292  bsid_pkts);
1293 
1294  return from_frame->n_vectors;
1295 }
1296 
1297 /* *INDENT-OFF* */
1299  .function = sr_policy_rewrite_encaps,
1300  .name = "sr-pl-rewrite-encaps",
1301  .vector_size = sizeof (u32),
1302  .format_trace = format_sr_policy_rewrite_trace,
1303  .type = VLIB_NODE_TYPE_INTERNAL,
1304  .n_errors = SR_POLICY_REWRITE_N_ERROR,
1305  .error_strings = sr_policy_rewrite_error_strings,
1306  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1307  .next_nodes = {
1308 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1310 #undef _
1311  },
1312 };
1313 /* *INDENT-ON* */
1314 
1315 /**
1316  * @brief IPv4 encapsulation processing as per RFC2473
1317  */
1320  vlib_buffer_t * b0,
1321  ip6_header_t * ip0, ip4_header_t * ip0_encap)
1322 {
1323  u32 new_l0;
1324  ip6_sr_header_t *sr0;
1325 
1326  u32 checksum0;
1327 
1328  /* Inner IPv4: Decrement TTL & update checksum */
1329  ip0_encap->ttl -= 1;
1330  checksum0 = ip0_encap->checksum + clib_host_to_net_u16 (0x0100);
1331  checksum0 += checksum0 >= 0xffff;
1332  ip0_encap->checksum = checksum0;
1333 
1334  /* Outer IPv6: Update length, FL, proto */
1335  new_l0 = ip0->payload_length + clib_net_to_host_u16 (ip0_encap->length);
1336  ip0->payload_length = clib_host_to_net_u16 (new_l0);
1338  clib_host_to_net_u32 (0 | ((6 & 0xF) << 28) |
1339  ((ip0_encap->tos & 0xFF) << 20));
1340  if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1341  {
1342  sr0 = (void *) (ip0 + 1);
1343  sr0->protocol = IP_PROTOCOL_IP_IN_IP;
1344  }
1345  else
1346  ip0->protocol = IP_PROTOCOL_IP_IN_IP;
1347 }
1348 
1349 /**
1350  * @brief Graph node for applying a SR policy into an IPv4 packet. Encapsulation
1351  */
1352 static uword
1354  vlib_frame_t * from_frame)
1355 {
1356  ip6_sr_main_t *sm = &sr_main;
1357  u32 n_left_from, next_index, *from, *to_next;
1358 
1359  from = vlib_frame_vector_args (from_frame);
1360  n_left_from = from_frame->n_vectors;
1361 
1362  next_index = node->cached_next_index;
1363 
1364  int encap_pkts = 0, bsid_pkts = 0;
1365 
1366  while (n_left_from > 0)
1367  {
1368  u32 n_left_to_next;
1369 
1370  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1371 
1372  /* Quad - Loop */
1373  while (n_left_from >= 8 && n_left_to_next >= 4)
1374  {
1375  u32 bi0, bi1, bi2, bi3;
1376  vlib_buffer_t *b0, *b1, *b2, *b3;
1377  u32 next0, next1, next2, next3;
1378  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1379  ip6_header_t *ip0, *ip1, *ip2, *ip3;
1380  ip4_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
1381  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1382 
1383  /* Prefetch next iteration. */
1384  {
1385  vlib_buffer_t *p4, *p5, *p6, *p7;
1386 
1387  p4 = vlib_get_buffer (vm, from[4]);
1388  p5 = vlib_get_buffer (vm, from[5]);
1389  p6 = vlib_get_buffer (vm, from[6]);
1390  p7 = vlib_get_buffer (vm, from[7]);
1391 
1392  /* Prefetch the buffer header and packet for the N+2 loop iteration */
1393  vlib_prefetch_buffer_header (p4, LOAD);
1394  vlib_prefetch_buffer_header (p5, LOAD);
1395  vlib_prefetch_buffer_header (p6, LOAD);
1396  vlib_prefetch_buffer_header (p7, LOAD);
1397 
1402  }
1403 
1404  to_next[0] = bi0 = from[0];
1405  to_next[1] = bi1 = from[1];
1406  to_next[2] = bi2 = from[2];
1407  to_next[3] = bi3 = from[3];
1408  from += 4;
1409  to_next += 4;
1410  n_left_from -= 4;
1411  n_left_to_next -= 4;
1412 
1413  b0 = vlib_get_buffer (vm, bi0);
1414  b1 = vlib_get_buffer (vm, bi1);
1415  b2 = vlib_get_buffer (vm, bi2);
1416  b3 = vlib_get_buffer (vm, bi3);
1417 
1418  sl0 =
1420  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1421  sl1 =
1423  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1424  sl2 =
1426  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1427  sl3 =
1429  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1431  vec_len (sl0->rewrite));
1433  vec_len (sl1->rewrite));
1435  vec_len (sl2->rewrite));
1437  vec_len (sl3->rewrite));
1438 
1439  ip0_encap = vlib_buffer_get_current (b0);
1440  ip1_encap = vlib_buffer_get_current (b1);
1441  ip2_encap = vlib_buffer_get_current (b2);
1442  ip3_encap = vlib_buffer_get_current (b3);
1443 
1444  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1445  sl0->rewrite, vec_len (sl0->rewrite));
1446  clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
1447  sl1->rewrite, vec_len (sl1->rewrite));
1448  clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
1449  sl2->rewrite, vec_len (sl2->rewrite));
1450  clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
1451  sl3->rewrite, vec_len (sl3->rewrite));
1452 
1453  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1454  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1455  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1456  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1457 
1458  ip0 = vlib_buffer_get_current (b0);
1459  ip1 = vlib_buffer_get_current (b1);
1460  ip2 = vlib_buffer_get_current (b2);
1461  ip3 = vlib_buffer_get_current (b3);
1462 
1463  encaps_processing_v4 (node, b0, ip0, ip0_encap);
1464  encaps_processing_v4 (node, b1, ip1, ip1_encap);
1465  encaps_processing_v4 (node, b2, ip2, ip2_encap);
1466  encaps_processing_v4 (node, b3, ip3, ip3_encap);
1467 
1468  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1469  {
1471  {
1473  vlib_add_trace (vm, node, b0, sizeof (*tr));
1474  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1475  sizeof (tr->src.as_u8));
1476  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1477  sizeof (tr->dst.as_u8));
1478  }
1479 
1481  {
1483  vlib_add_trace (vm, node, b1, sizeof (*tr));
1484  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1485  sizeof (tr->src.as_u8));
1486  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1487  sizeof (tr->dst.as_u8));
1488  }
1489 
1491  {
1493  vlib_add_trace (vm, node, b2, sizeof (*tr));
1494  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1495  sizeof (tr->src.as_u8));
1496  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1497  sizeof (tr->dst.as_u8));
1498  }
1499 
1501  {
1503  vlib_add_trace (vm, node, b3, sizeof (*tr));
1504  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1505  sizeof (tr->src.as_u8));
1506  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1507  sizeof (tr->dst.as_u8));
1508  }
1509  }
1510 
1511  encap_pkts += 4;
1512  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1513  n_left_to_next, bi0, bi1, bi2, bi3,
1514  next0, next1, next2, next3);
1515  }
1516 
1517  /* Single loop for potentially the last three packets */
1518  while (n_left_from > 0 && n_left_to_next > 0)
1519  {
1520  u32 bi0;
1521  vlib_buffer_t *b0;
1522  ip6_header_t *ip0 = 0;
1523  ip4_header_t *ip0_encap = 0;
1524  ip6_sr_sl_t *sl0;
1525  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1526 
1527  bi0 = from[0];
1528  to_next[0] = bi0;
1529  from += 1;
1530  to_next += 1;
1531  n_left_from -= 1;
1532  n_left_to_next -= 1;
1533  b0 = vlib_get_buffer (vm, bi0);
1534 
1535  sl0 =
1537  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1539  vec_len (sl0->rewrite));
1540 
1541  ip0_encap = vlib_buffer_get_current (b0);
1542 
1543  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
1544  sl0->rewrite, vec_len (sl0->rewrite));
1545  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1546 
1547  ip0 = vlib_buffer_get_current (b0);
1548 
1549  encaps_processing_v4 (node, b0, ip0, ip0_encap);
1550 
1551  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1553  {
1555  vlib_add_trace (vm, node, b0, sizeof (*tr));
1556  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1557  sizeof (tr->src.as_u8));
1558  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1559  sizeof (tr->dst.as_u8));
1560  }
1561 
1562  encap_pkts++;
1563  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1564  n_left_to_next, bi0, next0);
1565  }
1566 
1567  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1568  }
1569 
1570  /* Update counters */
1572  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1573  encap_pkts);
1575  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
1576  bsid_pkts);
1577 
1578  return from_frame->n_vectors;
1579 }
1580 
1581 /* *INDENT-OFF* */
1583  .function = sr_policy_rewrite_encaps_v4,
1584  .name = "sr-pl-rewrite-encaps-v4",
1585  .vector_size = sizeof (u32),
1586  .format_trace = format_sr_policy_rewrite_trace,
1587  .type = VLIB_NODE_TYPE_INTERNAL,
1588  .n_errors = SR_POLICY_REWRITE_N_ERROR,
1589  .error_strings = sr_policy_rewrite_error_strings,
1590  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
1591  .next_nodes = {
1592 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
1594 #undef _
1595  },
1596 };
1597 /* *INDENT-ON* */
1598 
1600 ip_flow_hash (void *data)
1601 {
1602  ip4_header_t *iph = (ip4_header_t *) data;
1603 
1604  if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
1606  else
1608 }
1609 
1612 {
1613  return (*((u64 *) m) & 0xffffffffffff);
1614 }
1615 
1618 {
1619  ethernet_header_t *eh;
1620  u64 a, b, c;
1621  uword is_ip, eh_size;
1622  u16 eh_type;
1623 
1624  eh = vlib_buffer_get_current (b0);
1625  eh_type = clib_net_to_host_u16 (eh->type);
1626  eh_size = ethernet_buffer_header_size (b0);
1627 
1628  is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
1629 
1630  /* since we have 2 cache lines, use them */
1631  if (is_ip)
1632  a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
1633  else
1634  a = eh->type;
1635 
1636  b = mac_to_u64 ((u8 *) eh->dst_address);
1637  c = mac_to_u64 ((u8 *) eh->src_address);
1638  hash_mix64 (a, b, c);
1639 
1640  return (u32) c;
1641 }
1642 
1643 /**
1644  * @brief Graph node for applying a SR policy into a L2 frame
1645  */
1646 static uword
1648  vlib_frame_t * from_frame)
1649 {
1650  ip6_sr_main_t *sm = &sr_main;
1651  u32 n_left_from, next_index, *from, *to_next;
1652 
1653  from = vlib_frame_vector_args (from_frame);
1654  n_left_from = from_frame->n_vectors;
1655 
1656  next_index = node->cached_next_index;
1657 
1658  int encap_pkts = 0, bsid_pkts = 0;
1659 
1660  while (n_left_from > 0)
1661  {
1662  u32 n_left_to_next;
1663 
1664  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1665 
1666  /* Quad - Loop */
1667  while (n_left_from >= 8 && n_left_to_next >= 4)
1668  {
1669  u32 bi0, bi1, bi2, bi3;
1670  vlib_buffer_t *b0, *b1, *b2, *b3;
1671  u32 next0, next1, next2, next3;
1672  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1673  ethernet_header_t *en0, *en1, *en2, *en3;
1674  ip6_header_t *ip0, *ip1, *ip2, *ip3;
1675  ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
1676  ip6_sr_policy_t *sp0, *sp1, *sp2, *sp3;
1677  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
1678 
1679  /* Prefetch next iteration. */
1680  {
1681  vlib_buffer_t *p4, *p5, *p6, *p7;
1682 
1683  p4 = vlib_get_buffer (vm, from[4]);
1684  p5 = vlib_get_buffer (vm, from[5]);
1685  p6 = vlib_get_buffer (vm, from[6]);
1686  p7 = vlib_get_buffer (vm, from[7]);
1687 
1688  /* Prefetch the buffer header and packet for the N+2 loop iteration */
1689  vlib_prefetch_buffer_header (p4, LOAD);
1690  vlib_prefetch_buffer_header (p5, LOAD);
1691  vlib_prefetch_buffer_header (p6, LOAD);
1692  vlib_prefetch_buffer_header (p7, LOAD);
1693 
1698  }
1699 
1700  to_next[0] = bi0 = from[0];
1701  to_next[1] = bi1 = from[1];
1702  to_next[2] = bi2 = from[2];
1703  to_next[3] = bi3 = from[3];
1704  from += 4;
1705  to_next += 4;
1706  n_left_from -= 4;
1707  n_left_to_next -= 4;
1708 
1709  b0 = vlib_get_buffer (vm, bi0);
1710  b1 = vlib_get_buffer (vm, bi1);
1711  b2 = vlib_get_buffer (vm, bi2);
1712  b3 = vlib_get_buffer (vm, bi3);
1713 
1714  sp0 = pool_elt_at_index (sm->sr_policies,
1716  (b0)->sw_if_index
1717  [VLIB_RX]]);
1718 
1719  sp1 = pool_elt_at_index (sm->sr_policies,
1721  (b1)->sw_if_index
1722  [VLIB_RX]]);
1723 
1724  sp2 = pool_elt_at_index (sm->sr_policies,
1726  (b2)->sw_if_index
1727  [VLIB_RX]]);
1728 
1729  sp3 = pool_elt_at_index (sm->sr_policies,
1731  (b3)->sw_if_index
1732  [VLIB_RX]]);
1733 
1734  if (vec_len (sp0->segments_lists) == 1)
1735  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1736  else
1737  {
1738  vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1739  vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1740  sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1741  (vec_len (sp0->segments_lists) - 1))];
1742  }
1743 
1744  if (vec_len (sp1->segments_lists) == 1)
1745  vnet_buffer (b1)->ip.adj_index[VLIB_TX] = sp1->segments_lists[1];
1746  else
1747  {
1748  vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1);
1749  vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
1750  sp1->segments_lists[(vnet_buffer (b1)->ip.flow_hash &
1751  (vec_len (sp1->segments_lists) - 1))];
1752  }
1753 
1754  if (vec_len (sp2->segments_lists) == 1)
1755  vnet_buffer (b2)->ip.adj_index[VLIB_TX] = sp2->segments_lists[2];
1756  else
1757  {
1758  vnet_buffer (b2)->ip.flow_hash = l2_flow_hash (b2);
1759  vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
1760  sp2->segments_lists[(vnet_buffer (b2)->ip.flow_hash &
1761  (vec_len (sp2->segments_lists) - 1))];
1762  }
1763 
1764  if (vec_len (sp3->segments_lists) == 1)
1765  vnet_buffer (b3)->ip.adj_index[VLIB_TX] = sp3->segments_lists[3];
1766  else
1767  {
1768  vnet_buffer (b3)->ip.flow_hash = l2_flow_hash (b3);
1769  vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
1770  sp3->segments_lists[(vnet_buffer (b3)->ip.flow_hash &
1771  (vec_len (sp3->segments_lists) - 1))];
1772  }
1773 
1774  sl0 =
1776  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1777  sl1 =
1779  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
1780  sl2 =
1782  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
1783  sl3 =
1785  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
1786 
1788  vec_len (sl0->rewrite));
1790  vec_len (sl1->rewrite));
1792  vec_len (sl2->rewrite));
1794  vec_len (sl3->rewrite));
1795 
1796  en0 = vlib_buffer_get_current (b0);
1797  en1 = vlib_buffer_get_current (b1);
1798  en2 = vlib_buffer_get_current (b2);
1799  en3 = vlib_buffer_get_current (b3);
1800 
1801  clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1802  vec_len (sl0->rewrite));
1803  clib_memcpy (((u8 *) en1) - vec_len (sl1->rewrite), sl1->rewrite,
1804  vec_len (sl1->rewrite));
1805  clib_memcpy (((u8 *) en2) - vec_len (sl2->rewrite), sl2->rewrite,
1806  vec_len (sl2->rewrite));
1807  clib_memcpy (((u8 *) en3) - vec_len (sl3->rewrite), sl3->rewrite,
1808  vec_len (sl3->rewrite));
1809 
1810  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1811  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
1812  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
1813  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
1814 
1815  ip0 = vlib_buffer_get_current (b0);
1816  ip1 = vlib_buffer_get_current (b1);
1817  ip2 = vlib_buffer_get_current (b2);
1818  ip3 = vlib_buffer_get_current (b3);
1819 
1820  ip0->payload_length =
1821  clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1822  ip1->payload_length =
1823  clib_host_to_net_u16 (b1->current_length - sizeof (ip6_header_t));
1824  ip2->payload_length =
1825  clib_host_to_net_u16 (b2->current_length - sizeof (ip6_header_t));
1826  ip3->payload_length =
1827  clib_host_to_net_u16 (b3->current_length - sizeof (ip6_header_t));
1828 
1829  if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1830  {
1831  sr0 = (void *) (ip0 + 1);
1832  sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1833  }
1834  else
1835  ip0->protocol = IP_PROTOCOL_IP6_NONXT;
1836 
1837  if (ip1->protocol == IP_PROTOCOL_IPV6_ROUTE)
1838  {
1839  sr1 = (void *) (ip1 + 1);
1840  sr1->protocol = IP_PROTOCOL_IP6_NONXT;
1841  }
1842  else
1843  ip1->protocol = IP_PROTOCOL_IP6_NONXT;
1844 
1845  if (ip2->protocol == IP_PROTOCOL_IPV6_ROUTE)
1846  {
1847  sr2 = (void *) (ip2 + 1);
1848  sr2->protocol = IP_PROTOCOL_IP6_NONXT;
1849  }
1850  else
1851  ip2->protocol = IP_PROTOCOL_IP6_NONXT;
1852 
1853  if (ip3->protocol == IP_PROTOCOL_IPV6_ROUTE)
1854  {
1855  sr3 = (void *) (ip3 + 1);
1856  sr3->protocol = IP_PROTOCOL_IP6_NONXT;
1857  }
1858  else
1859  ip3->protocol = IP_PROTOCOL_IP6_NONXT;
1860 
1861  /* Which Traffic class and flow label do I set ? */
1862  //ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32(0|((6&0xF)<<28)|((ip0_encap->tos&0xFF)<<20));
1863 
1864  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
1865  {
1867  {
1869  vlib_add_trace (vm, node, b0, sizeof (*tr));
1870  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1871  sizeof (tr->src.as_u8));
1872  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1873  sizeof (tr->dst.as_u8));
1874  }
1875 
1877  {
1879  vlib_add_trace (vm, node, b1, sizeof (*tr));
1880  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1881  sizeof (tr->src.as_u8));
1882  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1883  sizeof (tr->dst.as_u8));
1884  }
1885 
1887  {
1889  vlib_add_trace (vm, node, b2, sizeof (*tr));
1890  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
1891  sizeof (tr->src.as_u8));
1892  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
1893  sizeof (tr->dst.as_u8));
1894  }
1895 
1897  {
1899  vlib_add_trace (vm, node, b3, sizeof (*tr));
1900  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
1901  sizeof (tr->src.as_u8));
1902  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
1903  sizeof (tr->dst.as_u8));
1904  }
1905  }
1906 
1907  encap_pkts += 4;
1908  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
1909  n_left_to_next, bi0, bi1, bi2, bi3,
1910  next0, next1, next2, next3);
1911  }
1912 
1913  /* Single loop for potentially the last three packets */
1914  while (n_left_from > 0 && n_left_to_next > 0)
1915  {
1916  u32 bi0;
1917  vlib_buffer_t *b0;
1918  ip6_header_t *ip0 = 0;
1919  ip6_sr_header_t *sr0;
1920  ethernet_header_t *en0;
1921  ip6_sr_policy_t *sp0;
1922  ip6_sr_sl_t *sl0;
1923  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
1924 
1925  bi0 = from[0];
1926  to_next[0] = bi0;
1927  from += 1;
1928  to_next += 1;
1929  n_left_from -= 1;
1930  n_left_to_next -= 1;
1931  b0 = vlib_get_buffer (vm, bi0);
1932 
1933  /* Find the SR policy */
1934  sp0 = pool_elt_at_index (sm->sr_policies,
1936  (b0)->sw_if_index
1937  [VLIB_RX]]);
1938 
1939  /* In case there is more than one SL, LB among them */
1940  if (vec_len (sp0->segments_lists) == 1)
1941  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = sp0->segments_lists[0];
1942  else
1943  {
1944  vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0);
1945  vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
1946  sp0->segments_lists[(vnet_buffer (b0)->ip.flow_hash &
1947  (vec_len (sp0->segments_lists) - 1))];
1948  }
1949  sl0 =
1951  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1953  vec_len (sl0->rewrite));
1954 
1955  en0 = vlib_buffer_get_current (b0);
1956 
1957  clib_memcpy (((u8 *) en0) - vec_len (sl0->rewrite), sl0->rewrite,
1958  vec_len (sl0->rewrite));
1959 
1960  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
1961 
1962  ip0 = vlib_buffer_get_current (b0);
1963 
1964  ip0->payload_length =
1965  clib_host_to_net_u16 (b0->current_length - sizeof (ip6_header_t));
1966 
1967  if (ip0->protocol == IP_PROTOCOL_IPV6_ROUTE)
1968  {
1969  sr0 = (void *) (ip0 + 1);
1970  sr0->protocol = IP_PROTOCOL_IP6_NONXT;
1971  }
1972  else
1973  ip0->protocol = IP_PROTOCOL_IP6_NONXT;
1974 
1975  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
1977  {
1979  vlib_add_trace (vm, node, b0, sizeof (*tr));
1980  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1981  sizeof (tr->src.as_u8));
1982  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1983  sizeof (tr->dst.as_u8));
1984  }
1985 
1986  encap_pkts++;
1987  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1988  n_left_to_next, bi0, next0);
1989  }
1990 
1991  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1992  }
1993 
1994  /* Update counters */
1996  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
1997  encap_pkts);
1999  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2000  bsid_pkts);
2001 
2002  return from_frame->n_vectors;
2003 }
2004 
2005 /* *INDENT-OFF* */
2007  .function = sr_policy_rewrite_encaps_l2,
2008  .name = "sr-pl-rewrite-encaps-l2",
2009  .vector_size = sizeof (u32),
2010  .format_trace = format_sr_policy_rewrite_trace,
2011  .type = VLIB_NODE_TYPE_INTERNAL,
2012  .n_errors = SR_POLICY_REWRITE_N_ERROR,
2013  .error_strings = sr_policy_rewrite_error_strings,
2014  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2015  .next_nodes = {
2016 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2018 #undef _
2019  },
2020 };
2021 /* *INDENT-ON* */
2022 
2023 /**
2024  * @brief Graph node for applying a SR policy into a packet. SRH insertion.
2025  */
2026 static uword
2028  vlib_frame_t * from_frame)
2029 {
2030  ip6_sr_main_t *sm = &sr_main;
2031  u32 n_left_from, next_index, *from, *to_next;
2032 
2033  from = vlib_frame_vector_args (from_frame);
2034  n_left_from = from_frame->n_vectors;
2035 
2036  next_index = node->cached_next_index;
2037 
2038  int insert_pkts = 0, bsid_pkts = 0;
2039 
2040  while (n_left_from > 0)
2041  {
2042  u32 n_left_to_next;
2043 
2044  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2045 
2046  /* Quad - Loop */
2047  while (n_left_from >= 8 && n_left_to_next >= 4)
2048  {
2049  u32 bi0, bi1, bi2, bi3;
2050  vlib_buffer_t *b0, *b1, *b2, *b3;
2051  u32 next0, next1, next2, next3;
2052  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2053  ip6_header_t *ip0, *ip1, *ip2, *ip3;
2054  ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2055  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2056  u16 new_l0, new_l1, new_l2, new_l3;
2057 
2058  /* Prefetch next iteration. */
2059  {
2060  vlib_buffer_t *p4, *p5, *p6, *p7;
2061 
2062  p4 = vlib_get_buffer (vm, from[4]);
2063  p5 = vlib_get_buffer (vm, from[5]);
2064  p6 = vlib_get_buffer (vm, from[6]);
2065  p7 = vlib_get_buffer (vm, from[7]);
2066 
2067  /* Prefetch the buffer header and packet for the N+2 loop iteration */
2068  vlib_prefetch_buffer_header (p4, LOAD);
2069  vlib_prefetch_buffer_header (p5, LOAD);
2070  vlib_prefetch_buffer_header (p6, LOAD);
2071  vlib_prefetch_buffer_header (p7, LOAD);
2072 
2077  }
2078 
2079  to_next[0] = bi0 = from[0];
2080  to_next[1] = bi1 = from[1];
2081  to_next[2] = bi2 = from[2];
2082  to_next[3] = bi3 = from[3];
2083  from += 4;
2084  to_next += 4;
2085  n_left_from -= 4;
2086  n_left_to_next -= 4;
2087 
2088  b0 = vlib_get_buffer (vm, bi0);
2089  b1 = vlib_get_buffer (vm, bi1);
2090  b2 = vlib_get_buffer (vm, bi2);
2091  b3 = vlib_get_buffer (vm, bi3);
2092 
2093  sl0 =
2095  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2096  sl1 =
2098  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2099  sl2 =
2101  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2102  sl3 =
2104  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2106  vec_len (sl0->rewrite));
2108  vec_len (sl1->rewrite));
2110  vec_len (sl2->rewrite));
2112  vec_len (sl3->rewrite));
2113 
2114  ip0 = vlib_buffer_get_current (b0);
2115  ip1 = vlib_buffer_get_current (b1);
2116  ip2 = vlib_buffer_get_current (b2);
2117  ip3 = vlib_buffer_get_current (b3);
2118 
2119  if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2120  sr0 =
2121  (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2122  ip6_ext_header_len (ip0 + 1));
2123  else
2124  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2125 
2126  if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2127  sr1 =
2128  (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2129  ip6_ext_header_len (ip1 + 1));
2130  else
2131  sr1 = (ip6_sr_header_t *) (ip1 + 1);
2132 
2133  if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2134  sr2 =
2135  (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2136  ip6_ext_header_len (ip2 + 1));
2137  else
2138  sr2 = (ip6_sr_header_t *) (ip2 + 1);
2139 
2140  if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2141  sr3 =
2142  (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2143  ip6_ext_header_len (ip3 + 1));
2144  else
2145  sr3 = (ip6_sr_header_t *) (ip3 + 1);
2146 
2147  clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2148  (void *) sr0 - (void *) ip0);
2149  clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite), (u8 *) ip1,
2150  (void *) sr1 - (void *) ip1);
2151  clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite), (u8 *) ip2,
2152  (void *) sr2 - (void *) ip2);
2153  clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite), (u8 *) ip3,
2154  (void *) sr3 - (void *) ip3);
2155 
2156  clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2157  vec_len (sl0->rewrite));
2158  clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite)), sl1->rewrite,
2159  vec_len (sl1->rewrite));
2160  clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite)), sl2->rewrite,
2161  vec_len (sl2->rewrite));
2162  clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite)), sl3->rewrite,
2163  vec_len (sl3->rewrite));
2164 
2165  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2166  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
2167  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
2168  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
2169 
2170  ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2171  ip1 = ((void *) ip1) - vec_len (sl1->rewrite);
2172  ip2 = ((void *) ip2) - vec_len (sl2->rewrite);
2173  ip3 = ((void *) ip3) - vec_len (sl3->rewrite);
2174 
2175  ip0->hop_limit -= 1;
2176  ip1->hop_limit -= 1;
2177  ip2->hop_limit -= 1;
2178  ip3->hop_limit -= 1;
2179 
2180  new_l0 =
2181  clib_net_to_host_u16 (ip0->payload_length) +
2182  vec_len (sl0->rewrite);
2183  new_l1 =
2184  clib_net_to_host_u16 (ip1->payload_length) +
2185  vec_len (sl1->rewrite);
2186  new_l2 =
2187  clib_net_to_host_u16 (ip2->payload_length) +
2188  vec_len (sl2->rewrite);
2189  new_l3 =
2190  clib_net_to_host_u16 (ip3->payload_length) +
2191  vec_len (sl3->rewrite);
2192 
2193  ip0->payload_length = clib_host_to_net_u16 (new_l0);
2194  ip1->payload_length = clib_host_to_net_u16 (new_l1);
2195  ip2->payload_length = clib_host_to_net_u16 (new_l2);
2196  ip3->payload_length = clib_host_to_net_u16 (new_l3);
2197 
2198  sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2199  sr1 = ((void *) sr1) - vec_len (sl1->rewrite);
2200  sr2 = ((void *) sr2) - vec_len (sl2->rewrite);
2201  sr3 = ((void *) sr3) - vec_len (sl3->rewrite);
2202 
2203  sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2204  sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2205  sr1->segments->as_u64[0] = ip1->dst_address.as_u64[0];
2206  sr1->segments->as_u64[1] = ip1->dst_address.as_u64[1];
2207  sr2->segments->as_u64[0] = ip2->dst_address.as_u64[0];
2208  sr2->segments->as_u64[1] = ip2->dst_address.as_u64[1];
2209  sr3->segments->as_u64[0] = ip3->dst_address.as_u64[0];
2210  sr3->segments->as_u64[1] = ip3->dst_address.as_u64[1];
2211 
2212  ip0->dst_address.as_u64[0] =
2213  (sr0->segments + sr0->segments_left)->as_u64[0];
2214  ip0->dst_address.as_u64[1] =
2215  (sr0->segments + sr0->segments_left)->as_u64[1];
2216  ip1->dst_address.as_u64[0] =
2217  (sr1->segments + sr1->segments_left)->as_u64[0];
2218  ip1->dst_address.as_u64[1] =
2219  (sr1->segments + sr1->segments_left)->as_u64[1];
2220  ip2->dst_address.as_u64[0] =
2221  (sr2->segments + sr2->segments_left)->as_u64[0];
2222  ip2->dst_address.as_u64[1] =
2223  (sr2->segments + sr2->segments_left)->as_u64[1];
2224  ip3->dst_address.as_u64[0] =
2225  (sr3->segments + sr3->segments_left)->as_u64[0];
2226  ip3->dst_address.as_u64[1] =
2227  (sr3->segments + sr3->segments_left)->as_u64[1];
2228 
2229  ip6_ext_header_t *ip_ext;
2230  if (ip0 + 1 == (void *) sr0)
2231  {
2232  sr0->protocol = ip0->protocol;
2233  ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2234  }
2235  else
2236  {
2237  ip_ext = (void *) (ip0 + 1);
2238  sr0->protocol = ip_ext->next_hdr;
2239  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2240  }
2241 
2242  if (ip1 + 1 == (void *) sr1)
2243  {
2244  sr1->protocol = ip1->protocol;
2245  ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2246  }
2247  else
2248  {
2249  ip_ext = (void *) (ip2 + 1);
2250  sr2->protocol = ip_ext->next_hdr;
2251  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2252  }
2253 
2254  if (ip2 + 1 == (void *) sr2)
2255  {
2256  sr2->protocol = ip2->protocol;
2257  ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2258  }
2259  else
2260  {
2261  ip_ext = (void *) (ip2 + 1);
2262  sr2->protocol = ip_ext->next_hdr;
2263  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2264  }
2265 
2266  if (ip3 + 1 == (void *) sr3)
2267  {
2268  sr3->protocol = ip3->protocol;
2269  ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2270  }
2271  else
2272  {
2273  ip_ext = (void *) (ip3 + 1);
2274  sr3->protocol = ip_ext->next_hdr;
2275  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2276  }
2277 
2278  insert_pkts += 4;
2279 
2280  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2281  {
2283  {
2285  vlib_add_trace (vm, node, b0, sizeof (*tr));
2286  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2287  sizeof (tr->src.as_u8));
2288  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2289  sizeof (tr->dst.as_u8));
2290  }
2291 
2293  {
2295  vlib_add_trace (vm, node, b1, sizeof (*tr));
2296  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2297  sizeof (tr->src.as_u8));
2298  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2299  sizeof (tr->dst.as_u8));
2300  }
2301 
2303  {
2305  vlib_add_trace (vm, node, b2, sizeof (*tr));
2306  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2307  sizeof (tr->src.as_u8));
2308  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2309  sizeof (tr->dst.as_u8));
2310  }
2311 
2313  {
2315  vlib_add_trace (vm, node, b3, sizeof (*tr));
2316  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2317  sizeof (tr->src.as_u8));
2318  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2319  sizeof (tr->dst.as_u8));
2320  }
2321  }
2322 
2323  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2324  n_left_to_next, bi0, bi1, bi2, bi3,
2325  next0, next1, next2, next3);
2326  }
2327 
2328  /* Single loop for potentially the last three packets */
2329  while (n_left_from > 0 && n_left_to_next > 0)
2330  {
2331  u32 bi0;
2332  vlib_buffer_t *b0;
2333  ip6_header_t *ip0 = 0;
2334  ip6_sr_header_t *sr0 = 0;
2335  ip6_sr_sl_t *sl0;
2336  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2337  u16 new_l0 = 0;
2338 
2339  bi0 = from[0];
2340  to_next[0] = bi0;
2341  from += 1;
2342  to_next += 1;
2343  n_left_from -= 1;
2344  n_left_to_next -= 1;
2345 
2346  b0 = vlib_get_buffer (vm, bi0);
2347  sl0 =
2349  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2351  vec_len (sl0->rewrite));
2352 
2353  ip0 = vlib_buffer_get_current (b0);
2354 
2355  if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2356  sr0 =
2357  (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2358  ip6_ext_header_len (ip0 + 1));
2359  else
2360  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2361 
2362  clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite), (u8 *) ip0,
2363  (void *) sr0 - (void *) ip0);
2364  clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite)), sl0->rewrite,
2365  vec_len (sl0->rewrite));
2366 
2367  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
2368 
2369  ip0 = ((void *) ip0) - vec_len (sl0->rewrite);
2370  ip0->hop_limit -= 1;
2371  new_l0 =
2372  clib_net_to_host_u16 (ip0->payload_length) +
2373  vec_len (sl0->rewrite);
2374  ip0->payload_length = clib_host_to_net_u16 (new_l0);
2375 
2376  sr0 = ((void *) sr0) - vec_len (sl0->rewrite);
2377  sr0->segments->as_u64[0] = ip0->dst_address.as_u64[0];
2378  sr0->segments->as_u64[1] = ip0->dst_address.as_u64[1];
2379 
2380  ip0->dst_address.as_u64[0] =
2381  (sr0->segments + sr0->segments_left)->as_u64[0];
2382  ip0->dst_address.as_u64[1] =
2383  (sr0->segments + sr0->segments_left)->as_u64[1];
2384 
2385  if (ip0 + 1 == (void *) sr0)
2386  {
2387  sr0->protocol = ip0->protocol;
2388  ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2389  }
2390  else
2391  {
2392  ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2393  sr0->protocol = ip_ext->next_hdr;
2394  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2395  }
2396 
2397  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2399  {
2401  vlib_add_trace (vm, node, b0, sizeof (*tr));
2402  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2403  sizeof (tr->src.as_u8));
2404  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2405  sizeof (tr->dst.as_u8));
2406  }
2407 
2408  insert_pkts++;
2409 
2410  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2411  n_left_to_next, bi0, next0);
2412  }
2413 
2414  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2415  }
2416 
2417  /* Update counters */
2419  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2420  insert_pkts);
2422  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2423  bsid_pkts);
2424  return from_frame->n_vectors;
2425 }
2426 
2427 /* *INDENT-OFF* */
2429  .function = sr_policy_rewrite_insert,
2430  .name = "sr-pl-rewrite-insert",
2431  .vector_size = sizeof (u32),
2432  .format_trace = format_sr_policy_rewrite_trace,
2433  .type = VLIB_NODE_TYPE_INTERNAL,
2434  .n_errors = SR_POLICY_REWRITE_N_ERROR,
2435  .error_strings = sr_policy_rewrite_error_strings,
2436  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2437  .next_nodes = {
2438 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2440 #undef _
2441  },
2442 };
2443 /* *INDENT-ON* */
2444 
2445 /**
2446  * @brief Graph node for applying a SR policy into a packet. BSID - SRH insertion.
2447  */
2448 static uword
2450  vlib_frame_t * from_frame)
2451 {
2452  ip6_sr_main_t *sm = &sr_main;
2453  u32 n_left_from, next_index, *from, *to_next;
2454 
2455  from = vlib_frame_vector_args (from_frame);
2456  n_left_from = from_frame->n_vectors;
2457 
2458  next_index = node->cached_next_index;
2459 
2460  int insert_pkts = 0, bsid_pkts = 0;
2461 
2462  while (n_left_from > 0)
2463  {
2464  u32 n_left_to_next;
2465 
2466  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2467 
2468  /* Quad - Loop */
2469  while (n_left_from >= 8 && n_left_to_next >= 4)
2470  {
2471  u32 bi0, bi1, bi2, bi3;
2472  vlib_buffer_t *b0, *b1, *b2, *b3;
2473  u32 next0, next1, next2, next3;
2474  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2475  ip6_header_t *ip0, *ip1, *ip2, *ip3;
2476  ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2477  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2478  u16 new_l0, new_l1, new_l2, new_l3;
2479 
2480  /* Prefetch next iteration. */
2481  {
2482  vlib_buffer_t *p4, *p5, *p6, *p7;
2483 
2484  p4 = vlib_get_buffer (vm, from[4]);
2485  p5 = vlib_get_buffer (vm, from[5]);
2486  p6 = vlib_get_buffer (vm, from[6]);
2487  p7 = vlib_get_buffer (vm, from[7]);
2488 
2489  /* Prefetch the buffer header and packet for the N+2 loop iteration */
2490  vlib_prefetch_buffer_header (p4, LOAD);
2491  vlib_prefetch_buffer_header (p5, LOAD);
2492  vlib_prefetch_buffer_header (p6, LOAD);
2493  vlib_prefetch_buffer_header (p7, LOAD);
2494 
2499  }
2500 
2501  to_next[0] = bi0 = from[0];
2502  to_next[1] = bi1 = from[1];
2503  to_next[2] = bi2 = from[2];
2504  to_next[3] = bi3 = from[3];
2505  from += 4;
2506  to_next += 4;
2507  n_left_from -= 4;
2508  n_left_to_next -= 4;
2509 
2510  b0 = vlib_get_buffer (vm, bi0);
2511  b1 = vlib_get_buffer (vm, bi1);
2512  b2 = vlib_get_buffer (vm, bi2);
2513  b3 = vlib_get_buffer (vm, bi3);
2514 
2515  sl0 =
2517  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2518  sl1 =
2520  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2521  sl2 =
2523  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2524  sl3 =
2526  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2528  vec_len (sl0->rewrite_bsid));
2530  vec_len (sl1->rewrite_bsid));
2532  vec_len (sl2->rewrite_bsid));
2534  vec_len (sl3->rewrite_bsid));
2535 
2536  ip0 = vlib_buffer_get_current (b0);
2537  ip1 = vlib_buffer_get_current (b1);
2538  ip2 = vlib_buffer_get_current (b2);
2539  ip3 = vlib_buffer_get_current (b3);
2540 
2541  if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2542  sr0 =
2543  (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2544  ip6_ext_header_len (ip0 + 1));
2545  else
2546  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2547 
2548  if (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2549  sr1 =
2550  (ip6_sr_header_t *) (((void *) (ip1 + 1)) +
2551  ip6_ext_header_len (ip1 + 1));
2552  else
2553  sr1 = (ip6_sr_header_t *) (ip1 + 1);
2554 
2555  if (ip2->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2556  sr2 =
2557  (ip6_sr_header_t *) (((void *) (ip2 + 1)) +
2558  ip6_ext_header_len (ip2 + 1));
2559  else
2560  sr2 = (ip6_sr_header_t *) (ip2 + 1);
2561 
2562  if (ip3->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2563  sr3 =
2564  (ip6_sr_header_t *) (((void *) (ip3 + 1)) +
2565  ip6_ext_header_len (ip3 + 1));
2566  else
2567  sr3 = (ip6_sr_header_t *) (ip3 + 1);
2568 
2569  clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2570  (void *) sr0 - (void *) ip0);
2571  clib_memcpy ((u8 *) ip1 - vec_len (sl1->rewrite_bsid), (u8 *) ip1,
2572  (void *) sr1 - (void *) ip1);
2573  clib_memcpy ((u8 *) ip2 - vec_len (sl2->rewrite_bsid), (u8 *) ip2,
2574  (void *) sr2 - (void *) ip2);
2575  clib_memcpy ((u8 *) ip3 - vec_len (sl3->rewrite_bsid), (u8 *) ip3,
2576  (void *) sr3 - (void *) ip3);
2577 
2578  clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2579  sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2580  clib_memcpy (((u8 *) sr1 - vec_len (sl1->rewrite_bsid)),
2581  sl1->rewrite_bsid, vec_len (sl1->rewrite_bsid));
2582  clib_memcpy (((u8 *) sr2 - vec_len (sl2->rewrite_bsid)),
2583  sl2->rewrite_bsid, vec_len (sl2->rewrite_bsid));
2584  clib_memcpy (((u8 *) sr3 - vec_len (sl3->rewrite_bsid)),
2585  sl3->rewrite_bsid, vec_len (sl3->rewrite_bsid));
2586 
2587  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2588  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite_bsid));
2589  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite_bsid));
2590  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite_bsid));
2591 
2592  ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2593  ip1 = ((void *) ip1) - vec_len (sl1->rewrite_bsid);
2594  ip2 = ((void *) ip2) - vec_len (sl2->rewrite_bsid);
2595  ip3 = ((void *) ip3) - vec_len (sl3->rewrite_bsid);
2596 
2597  ip0->hop_limit -= 1;
2598  ip1->hop_limit -= 1;
2599  ip2->hop_limit -= 1;
2600  ip3->hop_limit -= 1;
2601 
2602  new_l0 =
2603  clib_net_to_host_u16 (ip0->payload_length) +
2604  vec_len (sl0->rewrite_bsid);
2605  new_l1 =
2606  clib_net_to_host_u16 (ip1->payload_length) +
2607  vec_len (sl1->rewrite_bsid);
2608  new_l2 =
2609  clib_net_to_host_u16 (ip2->payload_length) +
2610  vec_len (sl2->rewrite_bsid);
2611  new_l3 =
2612  clib_net_to_host_u16 (ip3->payload_length) +
2613  vec_len (sl3->rewrite_bsid);
2614 
2615  ip0->payload_length = clib_host_to_net_u16 (new_l0);
2616  ip1->payload_length = clib_host_to_net_u16 (new_l1);
2617  ip2->payload_length = clib_host_to_net_u16 (new_l2);
2618  ip3->payload_length = clib_host_to_net_u16 (new_l3);
2619 
2620  sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2621  sr1 = ((void *) sr1) - vec_len (sl1->rewrite_bsid);
2622  sr2 = ((void *) sr2) - vec_len (sl2->rewrite_bsid);
2623  sr3 = ((void *) sr3) - vec_len (sl3->rewrite_bsid);
2624 
2625  ip0->dst_address.as_u64[0] =
2626  (sr0->segments + sr0->segments_left)->as_u64[0];
2627  ip0->dst_address.as_u64[1] =
2628  (sr0->segments + sr0->segments_left)->as_u64[1];
2629  ip1->dst_address.as_u64[0] =
2630  (sr1->segments + sr1->segments_left)->as_u64[0];
2631  ip1->dst_address.as_u64[1] =
2632  (sr1->segments + sr1->segments_left)->as_u64[1];
2633  ip2->dst_address.as_u64[0] =
2634  (sr2->segments + sr2->segments_left)->as_u64[0];
2635  ip2->dst_address.as_u64[1] =
2636  (sr2->segments + sr2->segments_left)->as_u64[1];
2637  ip3->dst_address.as_u64[0] =
2638  (sr3->segments + sr3->segments_left)->as_u64[0];
2639  ip3->dst_address.as_u64[1] =
2640  (sr3->segments + sr3->segments_left)->as_u64[1];
2641 
2642  ip6_ext_header_t *ip_ext;
2643  if (ip0 + 1 == (void *) sr0)
2644  {
2645  sr0->protocol = ip0->protocol;
2646  ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2647  }
2648  else
2649  {
2650  ip_ext = (void *) (ip0 + 1);
2651  sr0->protocol = ip_ext->next_hdr;
2652  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2653  }
2654 
2655  if (ip1 + 1 == (void *) sr1)
2656  {
2657  sr1->protocol = ip1->protocol;
2658  ip1->protocol = IP_PROTOCOL_IPV6_ROUTE;
2659  }
2660  else
2661  {
2662  ip_ext = (void *) (ip2 + 1);
2663  sr2->protocol = ip_ext->next_hdr;
2664  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2665  }
2666 
2667  if (ip2 + 1 == (void *) sr2)
2668  {
2669  sr2->protocol = ip2->protocol;
2670  ip2->protocol = IP_PROTOCOL_IPV6_ROUTE;
2671  }
2672  else
2673  {
2674  ip_ext = (void *) (ip2 + 1);
2675  sr2->protocol = ip_ext->next_hdr;
2676  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2677  }
2678 
2679  if (ip3 + 1 == (void *) sr3)
2680  {
2681  sr3->protocol = ip3->protocol;
2682  ip3->protocol = IP_PROTOCOL_IPV6_ROUTE;
2683  }
2684  else
2685  {
2686  ip_ext = (void *) (ip3 + 1);
2687  sr3->protocol = ip_ext->next_hdr;
2688  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2689  }
2690 
2691  insert_pkts += 4;
2692 
2693  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2694  {
2696  {
2698  vlib_add_trace (vm, node, b0, sizeof (*tr));
2699  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2700  sizeof (tr->src.as_u8));
2701  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2702  sizeof (tr->dst.as_u8));
2703  }
2704 
2706  {
2708  vlib_add_trace (vm, node, b1, sizeof (*tr));
2709  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2710  sizeof (tr->src.as_u8));
2711  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2712  sizeof (tr->dst.as_u8));
2713  }
2714 
2716  {
2718  vlib_add_trace (vm, node, b2, sizeof (*tr));
2719  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
2720  sizeof (tr->src.as_u8));
2721  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
2722  sizeof (tr->dst.as_u8));
2723  }
2724 
2726  {
2728  vlib_add_trace (vm, node, b3, sizeof (*tr));
2729  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
2730  sizeof (tr->src.as_u8));
2731  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
2732  sizeof (tr->dst.as_u8));
2733  }
2734  }
2735 
2736  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
2737  n_left_to_next, bi0, bi1, bi2, bi3,
2738  next0, next1, next2, next3);
2739  }
2740 
2741  /* Single loop for potentially the last three packets */
2742  while (n_left_from > 0 && n_left_to_next > 0)
2743  {
2744  u32 bi0;
2745  vlib_buffer_t *b0;
2746  ip6_header_t *ip0 = 0;
2747  ip6_sr_header_t *sr0 = 0;
2748  ip6_sr_sl_t *sl0;
2749  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2750  u16 new_l0 = 0;
2751 
2752  bi0 = from[0];
2753  to_next[0] = bi0;
2754  from += 1;
2755  to_next += 1;
2756  n_left_from -= 1;
2757  n_left_to_next -= 1;
2758 
2759  b0 = vlib_get_buffer (vm, bi0);
2760  sl0 =
2762  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2764  vec_len (sl0->rewrite_bsid));
2765 
2766  ip0 = vlib_buffer_get_current (b0);
2767 
2768  if (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
2769  sr0 =
2770  (ip6_sr_header_t *) (((void *) (ip0 + 1)) +
2771  ip6_ext_header_len (ip0 + 1));
2772  else
2773  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2774 
2775  clib_memcpy ((u8 *) ip0 - vec_len (sl0->rewrite_bsid), (u8 *) ip0,
2776  (void *) sr0 - (void *) ip0);
2777  clib_memcpy (((u8 *) sr0 - vec_len (sl0->rewrite_bsid)),
2778  sl0->rewrite_bsid, vec_len (sl0->rewrite_bsid));
2779 
2780  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite_bsid));
2781 
2782  ip0 = ((void *) ip0) - vec_len (sl0->rewrite_bsid);
2783  ip0->hop_limit -= 1;
2784  new_l0 =
2785  clib_net_to_host_u16 (ip0->payload_length) +
2786  vec_len (sl0->rewrite_bsid);
2787  ip0->payload_length = clib_host_to_net_u16 (new_l0);
2788 
2789  sr0 = ((void *) sr0) - vec_len (sl0->rewrite_bsid);
2790 
2791  ip0->dst_address.as_u64[0] =
2792  (sr0->segments + sr0->segments_left)->as_u64[0];
2793  ip0->dst_address.as_u64[1] =
2794  (sr0->segments + sr0->segments_left)->as_u64[1];
2795 
2796  if (ip0 + 1 == (void *) sr0)
2797  {
2798  sr0->protocol = ip0->protocol;
2799  ip0->protocol = IP_PROTOCOL_IPV6_ROUTE;
2800  }
2801  else
2802  {
2803  ip6_ext_header_t *ip_ext = (void *) (ip0 + 1);
2804  sr0->protocol = ip_ext->next_hdr;
2805  ip_ext->next_hdr = IP_PROTOCOL_IPV6_ROUTE;
2806  }
2807 
2808  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
2810  {
2812  vlib_add_trace (vm, node, b0, sizeof (*tr));
2813  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2814  sizeof (tr->src.as_u8));
2815  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2816  sizeof (tr->dst.as_u8));
2817  }
2818 
2819  insert_pkts++;
2820 
2821  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2822  n_left_to_next, bi0, next0);
2823  }
2824 
2825  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2826  }
2827 
2828  /* Update counters */
2830  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
2831  insert_pkts);
2833  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
2834  bsid_pkts);
2835  return from_frame->n_vectors;
2836 }
2837 
2838 /* *INDENT-OFF* */
2840  .function = sr_policy_rewrite_b_insert,
2841  .name = "sr-pl-rewrite-b-insert",
2842  .vector_size = sizeof (u32),
2843  .format_trace = format_sr_policy_rewrite_trace,
2844  .type = VLIB_NODE_TYPE_INTERNAL,
2845  .n_errors = SR_POLICY_REWRITE_N_ERROR,
2846  .error_strings = sr_policy_rewrite_error_strings,
2847  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
2848  .next_nodes = {
2849 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
2851 #undef _
2852  },
2853 };
2854 /* *INDENT-ON* */
2855 
2856 /**
2857  * @brief Function BSID encapsulation
2858  */
2861  vlib_buffer_t * b0,
2862  ip6_header_t * ip0,
2863  ip6_sr_header_t * sr0, u32 * next0)
2864 {
2865  ip6_address_t *new_dst0;
2866 
2867  if (PREDICT_FALSE (!sr0))
2868  goto error_bsid_encaps;
2869 
2871  {
2872  if (PREDICT_TRUE (sr0->segments_left != 0))
2873  {
2874  sr0->segments_left -= 1;
2875  new_dst0 = (ip6_address_t *) (sr0->segments);
2876  new_dst0 += sr0->segments_left;
2877  ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2878  ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2879  return;
2880  }
2881  }
2882 
2883 error_bsid_encaps:
2884  *next0 = SR_POLICY_REWRITE_NEXT_ERROR;
2885  b0->error = node->errors[SR_POLICY_REWRITE_ERROR_BSID_ZERO];
2886 }
2887 
2888 /**
2889  * @brief Graph node for applying a SR policy BSID - Encapsulation
2890  */
2891 static uword
2893  vlib_frame_t * from_frame)
2894 {
2895  ip6_sr_main_t *sm = &sr_main;
2896  u32 n_left_from, next_index, *from, *to_next;
2897 
2898  from = vlib_frame_vector_args (from_frame);
2899  n_left_from = from_frame->n_vectors;
2900 
2901  next_index = node->cached_next_index;
2902 
2903  int encap_pkts = 0, bsid_pkts = 0;
2904 
2905  while (n_left_from > 0)
2906  {
2907  u32 n_left_to_next;
2908 
2909  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2910 
2911  /* Quad - Loop */
2912  while (n_left_from >= 8 && n_left_to_next >= 4)
2913  {
2914  u32 bi0, bi1, bi2, bi3;
2915  vlib_buffer_t *b0, *b1, *b2, *b3;
2916  u32 next0, next1, next2, next3;
2917  next0 = next1 = next2 = next3 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
2918  ip6_header_t *ip0, *ip1, *ip2, *ip3;
2919  ip6_header_t *ip0_encap, *ip1_encap, *ip2_encap, *ip3_encap;
2920  ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
2921  ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
2922  ip6_sr_sl_t *sl0, *sl1, *sl2, *sl3;
2923 
2924  /* Prefetch next iteration. */
2925  {
2926  vlib_buffer_t *p4, *p5, *p6, *p7;
2927 
2928  p4 = vlib_get_buffer (vm, from[4]);
2929  p5 = vlib_get_buffer (vm, from[5]);
2930  p6 = vlib_get_buffer (vm, from[6]);
2931  p7 = vlib_get_buffer (vm, from[7]);
2932 
2933  /* Prefetch the buffer header and packet for the N+2 loop iteration */
2934  vlib_prefetch_buffer_header (p4, LOAD);
2935  vlib_prefetch_buffer_header (p5, LOAD);
2936  vlib_prefetch_buffer_header (p6, LOAD);
2937  vlib_prefetch_buffer_header (p7, LOAD);
2938 
2943  }
2944 
2945  to_next[0] = bi0 = from[0];
2946  to_next[1] = bi1 = from[1];
2947  to_next[2] = bi2 = from[2];
2948  to_next[3] = bi3 = from[3];
2949  from += 4;
2950  to_next += 4;
2951  n_left_from -= 4;
2952  n_left_to_next -= 4;
2953 
2954  b0 = vlib_get_buffer (vm, bi0);
2955  b1 = vlib_get_buffer (vm, bi1);
2956  b2 = vlib_get_buffer (vm, bi2);
2957  b3 = vlib_get_buffer (vm, bi3);
2958 
2959  sl0 =
2961  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2962  sl1 =
2964  vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
2965  sl2 =
2967  vnet_buffer (b2)->ip.adj_index[VLIB_TX]);
2968  sl3 =
2970  vnet_buffer (b3)->ip.adj_index[VLIB_TX]);
2972  vec_len (sl0->rewrite));
2974  vec_len (sl1->rewrite));
2976  vec_len (sl2->rewrite));
2978  vec_len (sl3->rewrite));
2979 
2980  ip0_encap = vlib_buffer_get_current (b0);
2981  ip1_encap = vlib_buffer_get_current (b1);
2982  ip2_encap = vlib_buffer_get_current (b2);
2983  ip3_encap = vlib_buffer_get_current (b3);
2984 
2985  ip6_ext_header_find_t (ip0_encap, prev0, sr0,
2986  IP_PROTOCOL_IPV6_ROUTE);
2987  ip6_ext_header_find_t (ip1_encap, prev1, sr1,
2988  IP_PROTOCOL_IPV6_ROUTE);
2989  ip6_ext_header_find_t (ip2_encap, prev2, sr2,
2990  IP_PROTOCOL_IPV6_ROUTE);
2991  ip6_ext_header_find_t (ip3_encap, prev3, sr3,
2992  IP_PROTOCOL_IPV6_ROUTE);
2993 
2994  end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
2995  end_bsid_encaps_srh_processing (node, b1, ip1_encap, sr1, &next1);
2996  end_bsid_encaps_srh_processing (node, b2, ip2_encap, sr2, &next2);
2997  end_bsid_encaps_srh_processing (node, b3, ip3_encap, sr3, &next3);
2998 
2999  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3000  sl0->rewrite, vec_len (sl0->rewrite));
3001  clib_memcpy (((u8 *) ip1_encap) - vec_len (sl1->rewrite),
3002  sl1->rewrite, vec_len (sl1->rewrite));
3003  clib_memcpy (((u8 *) ip2_encap) - vec_len (sl2->rewrite),
3004  sl2->rewrite, vec_len (sl2->rewrite));
3005  clib_memcpy (((u8 *) ip3_encap) - vec_len (sl3->rewrite),
3006  sl3->rewrite, vec_len (sl3->rewrite));
3007 
3008  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3009  vlib_buffer_advance (b1, -(word) vec_len (sl1->rewrite));
3010  vlib_buffer_advance (b2, -(word) vec_len (sl2->rewrite));
3011  vlib_buffer_advance (b3, -(word) vec_len (sl3->rewrite));
3012 
3013  ip0 = vlib_buffer_get_current (b0);
3014  ip1 = vlib_buffer_get_current (b1);
3015  ip2 = vlib_buffer_get_current (b2);
3016  ip3 = vlib_buffer_get_current (b3);
3017 
3018  encaps_processing_v6 (node, b0, ip0, ip0_encap);
3019  encaps_processing_v6 (node, b1, ip1, ip1_encap);
3020  encaps_processing_v6 (node, b2, ip2, ip2_encap);
3021  encaps_processing_v6 (node, b3, ip3, ip3_encap);
3022 
3023  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
3024  {
3026  {
3028  vlib_add_trace (vm, node, b0, sizeof (*tr));
3029  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3030  sizeof (tr->src.as_u8));
3031  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3032  sizeof (tr->dst.as_u8));
3033  }
3034 
3036  {
3038  vlib_add_trace (vm, node, b1, sizeof (*tr));
3039  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
3040  sizeof (tr->src.as_u8));
3041  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
3042  sizeof (tr->dst.as_u8));
3043  }
3044 
3046  {
3048  vlib_add_trace (vm, node, b2, sizeof (*tr));
3049  clib_memcpy (tr->src.as_u8, ip2->src_address.as_u8,
3050  sizeof (tr->src.as_u8));
3051  clib_memcpy (tr->dst.as_u8, ip2->dst_address.as_u8,
3052  sizeof (tr->dst.as_u8));
3053  }
3054 
3056  {
3058  vlib_add_trace (vm, node, b3, sizeof (*tr));
3059  clib_memcpy (tr->src.as_u8, ip3->src_address.as_u8,
3060  sizeof (tr->src.as_u8));
3061  clib_memcpy (tr->dst.as_u8, ip3->dst_address.as_u8,
3062  sizeof (tr->dst.as_u8));
3063  }
3064  }
3065 
3066  encap_pkts += 4;
3067  vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
3068  n_left_to_next, bi0, bi1, bi2, bi3,
3069  next0, next1, next2, next3);
3070  }
3071 
3072  /* Single loop for potentially the last three packets */
3073  while (n_left_from > 0 && n_left_to_next > 0)
3074  {
3075  u32 bi0;
3076  vlib_buffer_t *b0;
3077  ip6_header_t *ip0 = 0, *ip0_encap = 0;
3078  ip6_ext_header_t *prev0;
3079  ip6_sr_header_t *sr0;
3080  ip6_sr_sl_t *sl0;
3081  u32 next0 = SR_POLICY_REWRITE_NEXT_IP6_LOOKUP;
3082 
3083  bi0 = from[0];
3084  to_next[0] = bi0;
3085  from += 1;
3086  to_next += 1;
3087  n_left_from -= 1;
3088  n_left_to_next -= 1;
3089  b0 = vlib_get_buffer (vm, bi0);
3090 
3091  sl0 =
3093  vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
3095  vec_len (sl0->rewrite));
3096 
3097  ip0_encap = vlib_buffer_get_current (b0);
3098  ip6_ext_header_find_t (ip0_encap, prev0, sr0,
3099  IP_PROTOCOL_IPV6_ROUTE);
3100  end_bsid_encaps_srh_processing (node, b0, ip0_encap, sr0, &next0);
3101 
3102  clib_memcpy (((u8 *) ip0_encap) - vec_len (sl0->rewrite),
3103  sl0->rewrite, vec_len (sl0->rewrite));
3104  vlib_buffer_advance (b0, -(word) vec_len (sl0->rewrite));
3105 
3106  ip0 = vlib_buffer_get_current (b0);
3107 
3108  encaps_processing_v6 (node, b0, ip0, ip0_encap);
3109 
3110  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE) &&
3112  {
3114  vlib_add_trace (vm, node, b0, sizeof (*tr));
3115  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
3116  sizeof (tr->src.as_u8));
3117  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
3118  sizeof (tr->dst.as_u8));
3119  }
3120 
3121  encap_pkts++;
3122  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
3123  n_left_to_next, bi0, next0);
3124  }
3125 
3126  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3127  }
3128 
3129  /* Update counters */
3131  SR_POLICY_REWRITE_ERROR_COUNTER_TOTAL,
3132  encap_pkts);
3134  SR_POLICY_REWRITE_ERROR_COUNTER_BSID,
3135  bsid_pkts);
3136 
3137  return from_frame->n_vectors;
3138 }
3139 
3140 /* *INDENT-OFF* */
3142  .function = sr_policy_rewrite_b_encaps,
3143  .name = "sr-pl-rewrite-b-encaps",
3144  .vector_size = sizeof (u32),
3145  .format_trace = format_sr_policy_rewrite_trace,
3146  .type = VLIB_NODE_TYPE_INTERNAL,
3147  .n_errors = SR_POLICY_REWRITE_N_ERROR,
3148  .error_strings = sr_policy_rewrite_error_strings,
3149  .n_next_nodes = SR_POLICY_REWRITE_N_NEXT,
3150  .next_nodes = {
3151 #define _(s,n) [SR_POLICY_REWRITE_NEXT_##s] = n,
3153 #undef _
3154  },
3155 };
3156 /* *INDENT-ON* */
3157 
3158 /*************************** SR Segment Lists DPOs ****************************/
3159 static u8 *
3160 format_sr_segment_list_dpo (u8 * s, va_list * args)
3161 {
3162  ip6_sr_main_t *sm = &sr_main;
3164  ip6_sr_sl_t *sl;
3165 
3166  index_t index = va_arg (*args, index_t);
3167  CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
3168  s = format (s, "SR: Segment List index:[%d]", index);
3169  s = format (s, "\n\tSegments:");
3170 
3171  sl = pool_elt_at_index (sm->sid_lists, index);
3172 
3173  s = format (s, "< ");
3174  vec_foreach (addr, sl->segments)
3175  {
3176  s = format (s, "%U, ", format_ip6_address, addr);
3177  }
3178  s = format (s, "\b\b > - ");
3179  s = format (s, "Weight: %u", sl->weight);
3180 
3181  return s;
3182 }
3183 
3184 const static dpo_vft_t sr_policy_rewrite_vft = {
3185  .dv_lock = sr_dpo_lock,
3186  .dv_unlock = sr_dpo_unlock,
3187  .dv_format = format_sr_segment_list_dpo,
3188 };
3189 
3190 const static char *const sr_pr_encaps_ip6_nodes[] = {
3191  "sr-pl-rewrite-encaps",
3192  NULL,
3193 };
3194 
3195 const static char *const sr_pr_encaps_ip4_nodes[] = {
3196  "sr-pl-rewrite-encaps-v4",
3197  NULL,
3198 };
3199 
3200 const static char *const *const sr_pr_encaps_nodes[DPO_PROTO_NUM] = {
3203 };
3204 
3205 const static char *const sr_pr_insert_ip6_nodes[] = {
3206  "sr-pl-rewrite-insert",
3207  NULL,
3208 };
3209 
3210 const static char *const *const sr_pr_insert_nodes[DPO_PROTO_NUM] = {
3212 };
3213 
3214 const static char *const sr_pr_bsid_insert_ip6_nodes[] = {
3215  "sr-pl-rewrite-b-insert",
3216  NULL,
3217 };
3218 
3219 const static char *const *const sr_pr_bsid_insert_nodes[DPO_PROTO_NUM] = {
3221 };
3222 
3223 const static char *const sr_pr_bsid_encaps_ip6_nodes[] = {
3224  "sr-pl-rewrite-b-encaps",
3225  NULL,
3226 };
3227 
3228 const static char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM] = {
3230 };
3231 
3232 /********************* SR Policy Rewrite initialization ***********************/
3233 /**
3234  * @brief SR Policy Rewrite initialization
3235  */
3236 clib_error_t *
3238 {
3239  ip6_sr_main_t *sm = &sr_main;
3240 
3241  /* Init memory for sr policy keys (bsid <-> ip6_address_t) */
3242  mhash_init (&sm->sr_policies_index_hash, sizeof (uword),
3243  sizeof (ip6_address_t));
3244 
3245  /* Init SR VPO DPOs type */
3247  dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_encaps_nodes);
3248 
3250  dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_insert_nodes);
3251 
3253  dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_encaps_nodes);
3254 
3256  dpo_register_new_type (&sr_policy_rewrite_vft, sr_pr_bsid_insert_nodes);
3257 
3258  /* Register the L2 encaps node used in HW redirect */
3260 
3261  sm->fib_table_ip6 = (u32) ~ 0;
3262  sm->fib_table_ip4 = (u32) ~ 0;
3263 
3264  return 0;
3265 }
3266 
3268 
3269 
3270 /*
3271 * fd.io coding-style-patch-verification: ON
3272 *
3273 * Local Variables:
3274 * eval: (c-set-style "gnu")
3275 * End:
3276 */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:432
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.
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:181
ip6_sr_main_t sr_main
Definition: sr.c:31
dpo_lock_fn_t dv_lock
A reference counting lock function.
Definition: dpo.h:382
sr_policy_rewrite_next_t
u8 type
Type (default is 0)
Definition: sr.h:86
#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:377
static uword sr_policy_rewrite_b_insert(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Graph node for applying a SR policy into a packet.
fib_node_index_t fib_table_lookup_exact_match(u32 fib_index, const fib_prefix_t *prefix)
Perfom an exact match in the non-forwarding table.
Definition: fib_table.c:95
a
Definition: bitmap.h:516
dpo_id_t path_dpo
ID of the Data-path object.
Definition: load_balance.h:66
u32 fib_table
FIB table.
Definition: sr.h: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:106
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:205
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:299
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:396
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.
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:52
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:518
#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:557
static ip6_sr_sl_t * create_sl(ip6_sr_policy_t *sr_policy, ip6_address_t *sl, u32 weight, u8 is_encap)
Creates a Segment List and adds it to an SR policy.
static const char *const *const sr_pr_bsid_encaps_nodes[DPO_PROTO_NUM]
#define IPv6_DEFAULT_HEADER_LENGTH
Definition: sr.h:33
u32 l2_sr_policy_rewrite_index
Definition: sr.h: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:415
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:225
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:947
index_t load_balance_create(u32 n_buckets, dpo_proto_t lb_proto, flow_hash_config_t fhc)
Definition: load_balance.c:194
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:68
#define static_always_inline
Definition: clib.h:93
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:438
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:92
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:171
Aggregrate type for a prefix.
Definition: fib_types.h:172
#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:494
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)
u32 fib_table_find(fib_protocol_t proto, u32 table_id)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1028
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:322
int sr_policy_del(ip6_address_t *bsid, u32 index)
Delete a SR policy.
#define SR_POLICY_TYPE_DEFAULT
Definition: sr_mpls.h:36
static void update_replicate(ip6_sr_policy_t *sr_policy)
Updates the Replicate DPO after an SR Policy change.
vlib_node_registration_t sr_policy_rewrite_b_insert_node
(constructor) VLIB_REGISTER_NODE (sr_policy_rewrite_b_insert_node)
Definition: fib_entry.h:242
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:459
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:72
static const char *const sr_pr_bsid_insert_ip6_nodes[]
void sr_set_source(ip6_address_t *address)
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:102
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:195
static u32 ip6_compute_flow_hash(const ip6_header_t *ip, flow_hash_config_t flow_hash_config)
Definition: ip6.h:414
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:271
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:370
#define PREDICT_FALSE(x)
Definition: clib.h:105
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:801
#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:218
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:364
void fib_table_unlock(u32 fib_index, fib_protocol_t proto, fib_source_t source)
Take a reference counting lock on the table.
Definition: fib_table.c:1180
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:1158
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:530
svmdb_client_t * c
u16 n_vectors
Definition: node.h:344
format_function_t format_ip6_address
Definition: format.h:95
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
vlib_main_t * vm
Definition: buffer.c:283
static const char *const sr_pr_bsid_encaps_ip6_nodes[]
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
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:93
#define clib_memcpy(a, b, c)
Definition: string.h:75
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:29
dpo_id_t bsid_dpo
DPO for Encaps/Insert for BSID.
Definition: sr.h:69
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:454
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:182
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:456
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:294
#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]
#define SR_POLICY_TYPE_SPRAY
Definition: sr_mpls.h:37
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:208
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
#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
#define SR_SEGMENT_LIST_WEIGHT_DEFAULT
Definition: sr_mpls.h:39
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:70
SRv6 and SR-MPLS.
Definition: fib_entry.h:58
u16 payload_length
Definition: ip6_packet.h:332
i64 word
Definition: types.h:111
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:30
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
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:267
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:326
Segment Routing data structures definitions.
Segment Routing main datastructure.
Definition: sr.h:189
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
dpo_id_t ip6_dpo
SR Policy specific DPO - IPv4.
Definition: sr.h:92
u8 data[0]
Packet data.
Definition: buffer.h:159
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:228
#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:450
vhost_vring_addr_t addr
Definition: vhost-user.h:83
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_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:75
#define IPv6_DEFAULT_HOP_LIMIT
Definition: sr.h:34
u32 fib_table_create_and_lock(fib_protocol_t proto, fib_source_t src, const char *const fmt,...)
Create a new table with no table ID.
Definition: fib_table.c:1106
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.
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128