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